From 6bd5bed29f3ebcc1155e615d7daa1c9cd1724efb Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 15 Jun 2019 18:54:19 -0400 Subject: added initial toolbar, splitter moved most of the text editor stuff to a new TextEditor class --- src/texteditor.h | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/texteditor.h (limited to 'src/texteditor.h') diff --git a/src/texteditor.h b/src/texteditor.h new file mode 100644 index 00000000..25a15ad7 --- /dev/null +++ b/src/texteditor.h @@ -0,0 +1,36 @@ +#ifndef MO_TEXTEDITOR_H +#define MO_TEXTEDITOR_H + +#include + +class TextEditor : public QObject +{ + Q_OBJECT + +public: + TextEditor(QPlainTextEdit* edit); + + bool load(const QString& filename); + bool save(); + + const QString& filename() const; + + void wordWrap(bool b); + bool wordWrap() const; + + bool dirty() const; + +signals: + void changed(bool b); + +private: + QPlainTextEdit* m_edit; + QString m_filename; + QString m_encoding; + bool m_dirty; + + void onChanged(bool b); + void dirty(bool b); +}; + +#endif // MO_TEXTEDITOR_H -- cgit v1.3.1 From 9f509f9aa2a1066a223bfd23fb54862f9c988b78 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 15 Jun 2019 19:36:55 -0400 Subject: TextEditor now has a dynamic toolbar --- src/modinfodialog.cpp | 31 --------------- src/modinfodialog.h | 5 --- src/modinfodialog.ui | 68 ++++----------------------------- src/texteditor.cpp | 102 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/texteditor.h | 29 +++++++++++++- 5 files changed, 132 insertions(+), 103 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index db5b5fd0..169623ad 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -361,14 +361,9 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo m_textFileEditor.reset(new TextEditor(ui->textFileView)); - connect( - m_textFileEditor.get(), &TextEditor::changed, - [&](bool b){ onTextFileChanged(b); }); - ui->tabTextSplitter->setSizes({200, 1}); ui->tabTextSplitter->setStretchFactor(0, 0); ui->tabTextSplitter->setStretchFactor(1, 1); - setTextFileWordWrap(true); // refresh everything but the conflict lists, which are done in exec() because // they depend on restoring the state to some widgets; this refresh has to be @@ -1092,7 +1087,6 @@ void ModInfoDialog::on_textFileList_currentItemChanged( void ModInfoDialog::openTextFile(const QString &fileName) { m_textFileEditor->load(fileName); - ui->textFileSave->setEnabled(false); } void ModInfoDialog::openIniFile(const QString &fileName) @@ -1169,26 +1163,9 @@ void ModInfoDialog::on_saveButton_clicked() saveCurrentIniFile(); } -void ModInfoDialog::on_textFileSave_clicked() -{ - saveCurrentTextFile(); -} - -void ModInfoDialog::on_textFileWordWrap_clicked() -{ - setTextFileWordWrap(!m_textFileEditor->wordWrap()); -} - -void ModInfoDialog::setTextFileWordWrap(bool b) -{ - m_textFileEditor->wordWrap(b); - ui->textFileWordWrap->setChecked(b); -} - void ModInfoDialog::saveCurrentTextFile() { m_textFileEditor->save(); - ui->textFileSave->setEnabled(false); } @@ -1211,20 +1188,12 @@ void ModInfoDialog::saveCurrentIniFile() ui->saveButton->setEnabled(false); } - void ModInfoDialog::on_iniFileView_textChanged() { QPushButton* saveButton = findChild("saveButton"); saveButton->setEnabled(true); } - -void ModInfoDialog::onTextFileChanged(bool b) -{ - ui->textFileSave->setEnabled(b); -} - - void ModInfoDialog::on_activateESP_clicked() { QListWidget *activeESPList = findChild("activeESPList"); diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 85226f45..42ef990d 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -220,15 +220,12 @@ private slots: void on_saveButton_clicked(); void on_activateESP_clicked(); void on_deactivateESP_clicked(); - void on_textFileSave_clicked(); - void on_textFileWordWrap_clicked(); void on_visitNexusLabel_linkActivated(const QString &link); void on_modIDEdit_editingFinished(); void on_sourceGameEdit_currentIndexChanged(int); void on_versionEdit_editingFinished(); void on_customUrlLineEdit_editingFinished(); void on_iniFileView_textChanged(); - void onTextFileChanged(bool b); void on_tabWidget_currentChanged(int index); void on_primaryCategoryBox_currentIndexChanged(int index); void on_categoriesTree_itemChanged(QTreeWidgetItem *item, int column); @@ -351,8 +348,6 @@ private: std::vector createGotoActions( const QList& selection); - - void setTextFileWordWrap(bool b); }; #endif // MODINFODIALOG_H diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 4a29f6e4..513506a7 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -46,67 +46,13 @@ A list of text-files in the mod directory like readmes. - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Save - - - - - - - Word wrap - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - - - - - + + + + + + + diff --git a/src/texteditor.cpp b/src/texteditor.cpp index eef74246..9de2b9c1 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -1,15 +1,18 @@ #include "texteditor.h" #include "utility.h" +#include TextEditor::TextEditor(QPlainTextEdit* edit) - : m_edit(edit), m_dirty(false) + : m_edit(edit), m_toolbar(*this), m_dirty(false) { + setupToolbar(); + m_edit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); wordWrap(true); QObject::connect( m_edit->document(), &QTextDocument::modificationChanged, - [&](bool b){ onChanged(b); }); + [&](bool b){ onModified(b); }); } bool TextEditor::load(const QString& filename) @@ -69,8 +72,99 @@ bool TextEditor::dirty() const return m_dirty; } -void TextEditor::onChanged(bool b) +void TextEditor::onModified(bool b) { dirty(b); - emit changed(b); + emit modified(b); +} + +void TextEditor::setupToolbar() +{ + auto* widget = wrapEditWidget(); + if (!widget) { + return; + } + + auto* layout = new QVBoxLayout(widget); + + // adding toolbar and edit + layout->addWidget(m_toolbar.widget()); + layout->addWidget(m_edit); + + // make the edit stretch + layout->setStretch(0, 0); + layout->setStretch(1, 1); + + // visuals + layout->setContentsMargins(0, 0, 0, 0); + widget->show(); +} + +QWidget* TextEditor::wrapEditWidget() +{ + auto widget = std::make_unique(); + + // wrapping the QPlainTextEdit into a new widget so the toolbar can be + // displayed above it + + if (auto* parentLayout=m_edit->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(m_edit->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()); + } else { + // unknown parent + qCritical("TextEditor: cannot wrap edit widget to display a toolbar"); + return nullptr; + } + + return widget.release(); +} + + +TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : + m_editor(editor), + m_widget(new QWidget), + m_save(new QAction(QObject::tr("&Save"))), + m_wordWrap(new QAction(QObject::tr("&Word wrap"))) +{ + QObject::connect(m_save, &QAction::triggered, [&]{ onSave(); }); + QObject::connect(m_wordWrap, &QAction::triggered, [&]{ onWordWrap(); }); + + auto* layout = new QHBoxLayout(m_widget); + layout->setContentsMargins(0, 0, 0, 0); + layout->setAlignment(Qt::AlignLeft); + + auto* b = new QToolButton; + b->setDefaultAction(m_save); + layout->addWidget(b); + + b = new QToolButton; + b->setDefaultAction(m_wordWrap); + layout->addWidget(b); + + QObject::connect(&m_editor, &TextEditor::modified, [&](bool b){ onTextModified(b); }); +} + +QWidget* TextEditorToolbar::widget() +{ + return m_widget; +} + +void TextEditorToolbar::onTextModified(bool b) +{ + m_save->setEnabled(b); +} + +void TextEditorToolbar::onSave() +{ + m_editor.save(); +} + +void TextEditorToolbar::onWordWrap() +{ + m_editor.wordWrap(!m_editor.wordWrap()); } diff --git a/src/texteditor.h b/src/texteditor.h index 25a15ad7..10f6c4de 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -3,6 +3,27 @@ #include +class TextEditor; + +class TextEditorToolbar +{ +public: + TextEditorToolbar(TextEditor& editor); + + QWidget* widget(); + +private: + TextEditor& m_editor; + QWidget* m_widget; + QAction* m_save; + QAction* m_wordWrap; + + void onTextModified(bool b); + void onSave(); + void onWordWrap(); +}; + + class TextEditor : public QObject { Q_OBJECT @@ -21,16 +42,20 @@ public: bool dirty() const; signals: - void changed(bool b); + void modified(bool b); private: QPlainTextEdit* m_edit; + TextEditorToolbar m_toolbar; QString m_filename; QString m_encoding; bool m_dirty; - void onChanged(bool b); + void onModified(bool b); void dirty(bool b); + + void setupToolbar(); + QWidget* wrapEditWidget(); }; #endif // MO_TEXTEDITOR_H -- cgit v1.3.1 From fc8d5c1708aa126bb3301079d15787943a0f47c9 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 15 Jun 2019 19:43:36 -0400 Subject: checkable wordwrap on toolbar --- src/texteditor.cpp | 25 ++++++++++++++++--------- src/texteditor.h | 5 +++-- 2 files changed, 19 insertions(+), 11 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 9de2b9c1..56ccfd2c 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -10,6 +10,8 @@ TextEditor::TextEditor(QPlainTextEdit* edit) m_edit->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); wordWrap(true); + emit modified(false); + QObject::connect( m_edit->document(), &QTextDocument::modificationChanged, [&](bool b){ onModified(b); }); @@ -55,6 +57,13 @@ void TextEditor::wordWrap(bool b) } else { m_edit->setLineWrapMode(QPlainTextEdit::NoWrap); } + + emit wordWrapChanged(b); +} + +void TextEditor::toggleWordWrap() +{ + wordWrap(!wordWrap()); } bool TextEditor::wordWrap() const @@ -131,8 +140,10 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : m_save(new QAction(QObject::tr("&Save"))), m_wordWrap(new QAction(QObject::tr("&Word wrap"))) { - QObject::connect(m_save, &QAction::triggered, [&]{ onSave(); }); - QObject::connect(m_wordWrap, &QAction::triggered, [&]{ onWordWrap(); }); + QObject::connect(m_save, &QAction::triggered, [&]{ m_editor.save(); }); + + m_wordWrap->setCheckable(true); + QObject::connect(m_wordWrap, &QAction::triggered, [&]{ m_editor.toggleWordWrap(); }); auto* layout = new QHBoxLayout(m_widget); layout->setContentsMargins(0, 0, 0, 0); @@ -147,6 +158,7 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : layout->addWidget(b); QObject::connect(&m_editor, &TextEditor::modified, [&](bool b){ onTextModified(b); }); + QObject::connect(&m_editor, &TextEditor::wordWrapChanged, [&](bool b){ onWordWrap(b); }); } QWidget* TextEditorToolbar::widget() @@ -159,12 +171,7 @@ void TextEditorToolbar::onTextModified(bool b) m_save->setEnabled(b); } -void TextEditorToolbar::onSave() -{ - m_editor.save(); -} - -void TextEditorToolbar::onWordWrap() +void TextEditorToolbar::onWordWrap(bool b) { - m_editor.wordWrap(!m_editor.wordWrap()); + m_wordWrap->setChecked(b); } diff --git a/src/texteditor.h b/src/texteditor.h index 10f6c4de..c196b7a4 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -19,8 +19,7 @@ private: QAction* m_wordWrap; void onTextModified(bool b); - void onSave(); - void onWordWrap(); + void onWordWrap(bool b); }; @@ -37,12 +36,14 @@ public: const QString& filename() const; void wordWrap(bool b); + void toggleWordWrap(); bool wordWrap() const; bool dirty() const; signals: void modified(bool b); + void wordWrapChanged(bool b); private: QPlainTextEdit* m_edit; -- cgit v1.3.1 From c79cf72d2250631110e8605ced6f34dda0378dc0 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sat, 15 Jun 2019 21:00:04 -0400 Subject: line numbers, which required inheriting from QPlainTextEdit instead --- src/modinfodialog.cpp | 12 ++-- src/modinfodialog.h | 1 - src/modinfodialog.ui | 14 ++--- src/texteditor.cpp | 148 +++++++++++++++++++++++++++++++++++++++++++------- src/texteditor.h | 33 +++++++++-- 5 files changed, 170 insertions(+), 38 deletions(-) (limited to 'src/texteditor.h') 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 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 @@ A list of text-files in the mod directory like readmes. - - - - - - - - + @@ -1217,6 +1210,11 @@ p, li { white-space: pre-wrap; } QLineEdit
modidlineedit.h
+ + TextEditor + QPlainTextEdit +
texteditor.h
+
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 -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(m_edit->parentWidget())) { + delete parentLayout->replaceWidget(this, widget.get()); + + } else if (auto* splitter=qobject_cast(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 -- cgit v1.3.1 From a2b68c3a2e17198e834684fe1719b19464559657 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 17 Jun 2019 01:11:13 -0400 Subject: text and background color, simple syntax highlighter that doesn't do anything highlight current line --- src/texteditor.cpp | 115 +++++++++++++++++++++++++++++++++++++++++++++++++++-- src/texteditor.h | 34 ++++++++++++++++ 2 files changed, 145 insertions(+), 4 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/texteditor.cpp b/src/texteditor.cpp index ecb46547..7a83e461 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -4,12 +4,14 @@ TextEditor::TextEditor(QWidget* parent) : QPlainTextEdit(parent), - m_toolbar(*this), m_lineNumbers(nullptr), m_dirty(false) + m_toolbar(*this), m_lineNumbers(nullptr), m_highlighter(nullptr), + m_dirty(false) { setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); wordWrap(true); m_lineNumbers = new TextEditorLineNumbers(*this); + m_highlighter = new TextEditorHighlighter(document()); emit modified(false); @@ -82,6 +84,48 @@ bool TextEditor::dirty() const return m_dirty; } +QString TextEditor::textColor() const +{ + return m_highlighter->textColor().name(QColor::HexArgb); +} + +void TextEditor::setTextColor(const QString& s) +{ + const QColor c(s); + if (!c.isValid()) { + qWarning() << "TextEditor: invalid text color '" << s << "'"; + return; + } + + m_highlighter->setTextColor(c); +} + +QString TextEditor::backgroundColor() const +{ + return m_highlighter->backgroundColor().name(QColor::HexArgb); +} + +void TextEditor::setBackgroundColor(const QString& s) +{ + const QColor c(s); + if (!c.isValid()) { + qWarning() << "TextEditor: invalid backgorund color '" << s << "'"; + return; + } + + if (m_highlighter->backgroundColor() == c) { + return; + } + + m_highlighter->setBackgroundColor(c); + + setStyleSheet(QString("QPlainTextEdit{ background-color: rgba(%1, %2, %3, %4); }") + .arg(c.redF() * 255) + .arg(c.greenF() * 255) + .arg(c.blueF() * 255) + .arg(c.alphaF())); +} + void TextEditor::onModified(bool b) { dirty(b); @@ -185,6 +229,50 @@ void TextEditor::paintLineNumbers(QPaintEvent* e) } +TextEditorHighlighter::TextEditorHighlighter(QTextDocument* doc) : + QSyntaxHighlighter(doc), + m_background(QColor("transparent")), + m_text(QColor("black")) +{ +} + +QColor TextEditorHighlighter::backgroundColor() +{ + return m_background; +} + +void TextEditorHighlighter::setBackgroundColor(const QColor& c) +{ + m_background = c; + changed(); +} + +QColor TextEditorHighlighter::textColor() +{ + return m_text; +} + +void TextEditorHighlighter::setTextColor(const QColor& c) +{ + m_text = c; + changed(); +} + +void TextEditorHighlighter::highlightBlock(const QString& s) +{ + QTextCharFormat f; + f.setBackground(m_background); + f.setForeground(m_text); + + setFormat(0, s.size(), f); +} + +void TextEditorHighlighter::changed() +{ + rehighlight(); +} + + TextEditorLineNumbers::TextEditorLineNumbers(TextEditor& editor) : QWidget(&editor), m_editor(editor) { @@ -192,10 +280,10 @@ TextEditorLineNumbers::TextEditorLineNumbers(TextEditor& editor) 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())); + connect(&m_editor, &QPlainTextEdit::cursorPositionChanged, [&]{ highlightCurrentLine(); }); updateAreaWidth(); - //highlightCurrentLine(); + highlightCurrentLine(); } QSize TextEditorLineNumbers::sizeHint() const @@ -211,7 +299,7 @@ void TextEditorLineNumbers::paintEvent(QPaintEvent* e) int TextEditorLineNumbers::areaWidth() const { int digits = 1; - int max = qMax(1, m_editor.blockCount()); + int max = std::max(1, m_editor.blockCount()); while (max >= 10) { max /= 10; @@ -243,6 +331,25 @@ void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) } } +void TextEditorLineNumbers::highlightCurrentLine() +{ + QList extraSelections; + + if (!m_editor.isReadOnly()) { + QTextEdit::ExtraSelection selection; + + QColor lineColor = QColor(Qt::yellow).lighter(160); + + selection.format.setBackground(lineColor); + selection.format.setProperty(QTextFormat::FullWidthSelection, true); + selection.cursor = m_editor.textCursor(); + selection.cursor.clearSelection(); + extraSelections.append(selection); + } + + m_editor.setExtraSelections(extraSelections); +} + TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : m_editor(editor), diff --git a/src/texteditor.h b/src/texteditor.h index af542341..0ae39c60 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -23,6 +23,8 @@ private: }; +// mostly from https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html +// class TextEditorLineNumbers : public QWidget { public: @@ -38,12 +40,37 @@ private: void updateAreaWidth(); void updateArea(const QRect &rect, int dy); + void highlightCurrentLine(); +}; + + +class TextEditorHighlighter : public QSyntaxHighlighter +{ +public: + TextEditorHighlighter(QTextDocument* doc); + + QColor backgroundColor(); + void setBackgroundColor(const QColor& c); + + QColor textColor(); + void setTextColor(const QColor& c); + +protected: + void highlightBlock(const QString& text) override; + +private: + QColor m_background, m_text; + + void changed(); }; class TextEditor : public QPlainTextEdit { Q_OBJECT + Q_PROPERTY(QString textColor READ textColor WRITE setTextColor) + Q_PROPERTY(QString backgroundColor READ backgroundColor WRITE setBackgroundColor) + friend class TextEditorLineNumbers; public: @@ -62,6 +89,12 @@ public: bool dirty() const; + QString textColor() const; + void setTextColor(const QString& s); + + QString backgroundColor() const; + void setBackgroundColor(const QString& s); + signals: void modified(bool b); void wordWrapChanged(bool b); @@ -72,6 +105,7 @@ protected: private: TextEditorToolbar m_toolbar; TextEditorLineNumbers* m_lineNumbers; + TextEditorHighlighter* m_highlighter; QString m_filename; QString m_encoding; bool m_dirty; -- cgit v1.3.1 From 0084ca6c4c1fad76dafe700aad3db4fdb5ef2750 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 17 Jun 2019 02:53:52 -0400 Subject: text editor default style changed colour properties to use an actual QColor stylable highlight background color padding for line numbers --- src/texteditor.cpp | 187 +++++++++++++++++++++++++++++++++++------------------ src/texteditor.h | 48 ++++++++++---- 2 files changed, 159 insertions(+), 76 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 7a83e461..ccafb37a 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -7,17 +7,53 @@ TextEditor::TextEditor(QWidget* parent) : m_toolbar(*this), m_lineNumbers(nullptr), m_highlighter(nullptr), m_dirty(false) { - setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - wordWrap(true); - m_lineNumbers = new TextEditorLineNumbers(*this); m_highlighter = new TextEditorHighlighter(document()); + setDefaultStyle(); + wordWrap(true); + emit modified(false); - QObject::connect( + connect( document(), &QTextDocument::modificationChanged, [&](bool b){ onModified(b); }); + + connect( + this, &QPlainTextEdit::cursorPositionChanged, + [&]{ highlightCurrentLine(); }); +} + +void TextEditor::setDefaultStyle() +{ + const auto font = QFontDatabase::systemFont(QFontDatabase::FixedFont); + + setFont(font); + m_lineNumbers->setFont(font); + + QColor textColor(Qt::black); + QColor altTextColor(Qt::darkGray); + QColor backgroundColor(Qt::white); + + { + auto w = std::make_unique(); + + if (auto* s=style()) { + s->polish(w.get()); + } + + textColor = w->palette().color(QPalette::WindowText); + altTextColor = w->palette().color(QPalette::Disabled, QPalette::WindowText); + backgroundColor = w->palette().color(QPalette::Window); + } + + setTextColor(textColor); + m_lineNumbers->setTextColor(altTextColor); + + setBackgroundColor(backgroundColor); + m_lineNumbers->setBackgroundColor(backgroundColor); + + setHighlightBackgroundColor(backgroundColor); } bool TextEditor::load(const QString& filename) @@ -84,35 +120,13 @@ bool TextEditor::dirty() const return m_dirty; } -QString TextEditor::textColor() const -{ - return m_highlighter->textColor().name(QColor::HexArgb); -} - -void TextEditor::setTextColor(const QString& s) +QColor TextEditor::backgroundColor() const { - const QColor c(s); - if (!c.isValid()) { - qWarning() << "TextEditor: invalid text color '" << s << "'"; - return; - } - - m_highlighter->setTextColor(c); + return m_highlighter->backgroundColor(); } -QString TextEditor::backgroundColor() const +void TextEditor::setBackgroundColor(const QColor& c) { - return m_highlighter->backgroundColor().name(QColor::HexArgb); -} - -void TextEditor::setBackgroundColor(const QString& s) -{ - const QColor c(s); - if (!c.isValid()) { - qWarning() << "TextEditor: invalid backgorund color '" << s << "'"; - return; - } - if (m_highlighter->backgroundColor() == c) { return; } @@ -126,6 +140,27 @@ void TextEditor::setBackgroundColor(const QString& s) .arg(c.alphaF())); } +QColor TextEditor::textColor() const +{ + return m_highlighter->textColor(); +} + +void TextEditor::setTextColor(const QColor& c) +{ + m_highlighter->setTextColor(c); +} + +QColor TextEditor::highlightBackgroundColor() const +{ + return m_highlightBackground; +} + +void TextEditor::setHighlightBackgroundColor(const QColor& c) +{ + m_highlightBackground = c; + update(); +} + void TextEditor::onModified(bool b) { dirty(b); @@ -201,10 +236,12 @@ void TextEditor::resizeEvent(QResizeEvent* e) m_lineNumbers->setGeometry(QRect(cr.left(), cr.top(), m_lineNumbers->areaWidth(), cr.height())); } -void TextEditor::paintLineNumbers(QPaintEvent* e) +void TextEditor::paintLineNumbers(QPaintEvent* e, const QColor& textColor) { + QStyleOption opt; + opt.init(m_lineNumbers); + QPainter painter(m_lineNumbers); - painter.fillRect(e->rect(), Qt::lightGray); QTextBlock block = firstVisibleBlock(); int blockNumber = block.blockNumber(); @@ -214,10 +251,10 @@ void TextEditor::paintLineNumbers(QPaintEvent* e) 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.setPen(textColor); painter.drawText( - 0, top, m_lineNumbers->width(), fontMetrics().height(), + 0, top, m_lineNumbers->width() - 3, fontMetrics().height(), Qt::AlignRight, number); } @@ -228,6 +265,25 @@ void TextEditor::paintLineNumbers(QPaintEvent* e) } } +void TextEditor::highlightCurrentLine() +{ + QList extraSelections; + + if (!isReadOnly()) { + QTextEdit::ExtraSelection selection; + + QColor lineColor = QColor(Qt::yellow).lighter(160); + + selection.format.setBackground(m_highlightBackground); + selection.format.setProperty(QTextFormat::FullWidthSelection, true); + selection.cursor = textCursor(); + selection.cursor.clearSelection(); + extraSelections.append(selection); + } + + setExtraSelections(extraSelections); +} + TextEditorHighlighter::TextEditorHighlighter(QTextDocument* doc) : QSyntaxHighlighter(doc), @@ -236,7 +292,7 @@ TextEditorHighlighter::TextEditorHighlighter(QTextDocument* doc) : { } -QColor TextEditorHighlighter::backgroundColor() +QColor TextEditorHighlighter::backgroundColor() const { return m_background; } @@ -247,7 +303,7 @@ void TextEditorHighlighter::setBackgroundColor(const QColor& c) changed(); } -QColor TextEditorHighlighter::textColor() +QColor TextEditorHighlighter::textColor() const { return m_text; } @@ -274,16 +330,14 @@ void TextEditorHighlighter::changed() TextEditorLineNumbers::TextEditorLineNumbers(TextEditor& editor) - : QWidget(&editor), m_editor(editor) + : QFrame(&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(&m_editor, &QPlainTextEdit::cursorPositionChanged, [&]{ highlightCurrentLine(); }); updateAreaWidth(); - highlightCurrentLine(); } QSize TextEditorLineNumbers::sizeHint() const @@ -291,11 +345,6 @@ QSize TextEditorLineNumbers::sizeHint() const return QSize(areaWidth(), 0); } -void TextEditorLineNumbers::paintEvent(QPaintEvent* e) -{ - m_editor.paintLineNumbers(e); -} - int TextEditorLineNumbers::areaWidth() const { int digits = 1; @@ -308,11 +357,42 @@ int TextEditorLineNumbers::areaWidth() const digits = std::max(3, digits); - int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits; + int space = 3 + fontMetrics().horizontalAdvance(QLatin1Char('9')) * digits + 3; return space; } +QColor TextEditorLineNumbers::textColor() const +{ + return m_text; +} + +void TextEditorLineNumbers::setTextColor(const QColor& c) +{ + m_text = c; + m_editor.update(); +} + +QColor TextEditorLineNumbers::backgroundColor() const +{ + return m_background; +} + +void TextEditorLineNumbers::setBackgroundColor(const QColor& c) +{ + m_background = c; + m_editor.update(); +} + +void TextEditorLineNumbers::paintEvent(QPaintEvent* e) +{ + QPainter painter(this); + painter.fillRect(e->rect(), m_background); + + QFrame::paintEvent(e); + m_editor.paintLineNumbers(e, m_text); +} + void TextEditorLineNumbers::updateAreaWidth() { m_editor.setViewportMargins(areaWidth(), 0, 0, 0); @@ -331,25 +411,6 @@ void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) } } -void TextEditorLineNumbers::highlightCurrentLine() -{ - QList extraSelections; - - if (!m_editor.isReadOnly()) { - QTextEdit::ExtraSelection selection; - - QColor lineColor = QColor(Qt::yellow).lighter(160); - - selection.format.setBackground(lineColor); - selection.format.setProperty(QTextFormat::FullWidthSelection, true); - selection.cursor = m_editor.textCursor(); - selection.cursor.clearSelection(); - extraSelections.append(selection); - } - - m_editor.setExtraSelections(extraSelections); -} - TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : m_editor(editor), diff --git a/src/texteditor.h b/src/texteditor.h index 0ae39c60..0f7447ff 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -5,8 +5,10 @@ class TextEditor; -class TextEditorToolbar +class TextEditorToolbar : public QObject { + Q_OBJECT; + public: TextEditorToolbar(TextEditor& editor); @@ -25,34 +27,47 @@ private: // mostly from https://doc.qt.io/qt-5/qtwidgets-widgets-codeeditor-example.html // -class TextEditorLineNumbers : public QWidget +class TextEditorLineNumbers : public QFrame { + Q_OBJECT; + Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor); + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor); + public: TextEditorLineNumbers(TextEditor& editor); + QSize sizeHint() const override; int areaWidth() const; + QColor textColor() const; + void setTextColor(const QColor& c); + + QColor backgroundColor() const; + void setBackgroundColor(const QColor& c); + protected: void paintEvent(QPaintEvent *event) override; private: TextEditor& m_editor; + QColor m_background, m_text; void updateAreaWidth(); void updateArea(const QRect &rect, int dy); - void highlightCurrentLine(); }; class TextEditorHighlighter : public QSyntaxHighlighter { + Q_OBJECT; + public: TextEditorHighlighter(QTextDocument* doc); - QColor backgroundColor(); + QColor backgroundColor() const; void setBackgroundColor(const QColor& c); - QColor textColor(); + QColor textColor() const; void setTextColor(const QColor& c); protected: @@ -67,9 +82,10 @@ private: class TextEditor : public QPlainTextEdit { - Q_OBJECT - Q_PROPERTY(QString textColor READ textColor WRITE setTextColor) - Q_PROPERTY(QString backgroundColor READ backgroundColor WRITE setBackgroundColor) + Q_OBJECT; + Q_PROPERTY(QColor textColor READ textColor WRITE setTextColor); + Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor); + Q_PROPERTY(QColor highlightBackgroundColor READ highlightBackgroundColor WRITE setHighlightBackgroundColor); friend class TextEditorLineNumbers; @@ -89,11 +105,14 @@ public: bool dirty() const; - QString textColor() const; - void setTextColor(const QString& s); + QColor backgroundColor() const; + void setBackgroundColor(const QColor& c); - QString backgroundColor() const; - void setBackgroundColor(const QString& s); + QColor textColor() const; + void setTextColor(const QColor& c); + + QColor highlightBackgroundColor() const; + void setHighlightBackgroundColor(const QColor& c); signals: void modified(bool b); @@ -106,16 +125,19 @@ private: TextEditorToolbar m_toolbar; TextEditorLineNumbers* m_lineNumbers; TextEditorHighlighter* m_highlighter; + QColor m_highlightBackground; QString m_filename; QString m_encoding; bool m_dirty; + void setDefaultStyle(); void onModified(bool b); void dirty(bool b); QWidget* wrapEditWidget(); - void paintLineNumbers(QPaintEvent* e); + void highlightCurrentLine(); + void paintLineNumbers(QPaintEvent* e, const QColor& textColor); }; #endif // MO_TEXTEDITOR_H -- cgit v1.3.1 From 491b96c0528159f0830e439f5c5a55e3ff09ad1a Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 17 Jun 2019 03:06:31 -0400 Subject: made TextEditorToolbar a widget added save and word wrap icons --- src/resources/save.svg | 1 + src/resources/word-wrap.svg | 1 + src/texteditor.cpp | 17 ++++++----------- src/texteditor.h | 7 ++----- 4 files changed, 10 insertions(+), 16 deletions(-) create mode 100644 src/resources/save.svg create mode 100644 src/resources/word-wrap.svg (limited to 'src/texteditor.h') diff --git a/src/resources/save.svg b/src/resources/save.svg new file mode 100644 index 00000000..3fb2a8df --- /dev/null +++ b/src/resources/save.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/resources/word-wrap.svg b/src/resources/word-wrap.svg new file mode 100644 index 00000000..63b1f1f0 --- /dev/null +++ b/src/resources/word-wrap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/texteditor.cpp b/src/texteditor.cpp index ccafb37a..78ce1610 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -4,9 +4,10 @@ TextEditor::TextEditor(QWidget* parent) : QPlainTextEdit(parent), - m_toolbar(*this), m_lineNumbers(nullptr), m_highlighter(nullptr), + m_toolbar(nullptr), m_lineNumbers(nullptr), m_highlighter(nullptr), m_dirty(false) { + m_toolbar = new TextEditorToolbar(*this); m_lineNumbers = new TextEditorLineNumbers(*this); m_highlighter = new TextEditorHighlighter(document()); @@ -177,7 +178,7 @@ void TextEditor::setupToolbar() auto* layout = new QVBoxLayout(widget); // adding toolbar and edit - layout->addWidget(m_toolbar.widget()); + layout->addWidget(m_toolbar); layout->addWidget(this); // make the edit stretch @@ -414,16 +415,15 @@ void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : m_editor(editor), - m_widget(new QWidget), - m_save(new QAction(QObject::tr("&Save"))), - m_wordWrap(new QAction(QObject::tr("&Word wrap"))) + m_save(new QAction(QIcon(":/MO/gui/save"), QObject::tr("&Save"))), + m_wordWrap(new QAction(QIcon(":/MO/gui/word-wrap"), QObject::tr("&Word wrap"))) { QObject::connect(m_save, &QAction::triggered, [&]{ m_editor.save(); }); m_wordWrap->setCheckable(true); QObject::connect(m_wordWrap, &QAction::triggered, [&]{ m_editor.toggleWordWrap(); }); - auto* layout = new QHBoxLayout(m_widget); + auto* layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setAlignment(Qt::AlignLeft); @@ -439,11 +439,6 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : QObject::connect(&m_editor, &TextEditor::wordWrapChanged, [&](bool b){ onWordWrap(b); }); } -QWidget* TextEditorToolbar::widget() -{ - return m_widget; -} - void TextEditorToolbar::onTextModified(bool b) { m_save->setEnabled(b); diff --git a/src/texteditor.h b/src/texteditor.h index 0f7447ff..eef5ca52 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -5,18 +5,15 @@ class TextEditor; -class TextEditorToolbar : public QObject +class TextEditorToolbar : public QFrame { Q_OBJECT; public: TextEditorToolbar(TextEditor& editor); - QWidget* widget(); - private: TextEditor& m_editor; - QWidget* m_widget; QAction* m_save; QAction* m_wordWrap; @@ -122,7 +119,7 @@ protected: void resizeEvent(QResizeEvent* e) override; private: - TextEditorToolbar m_toolbar; + TextEditorToolbar* m_toolbar; TextEditorLineNumbers* m_lineNumbers; TextEditorHighlighter* m_highlighter; QColor m_highlightBackground; -- cgit v1.3.1 From cbdc4cc3284f13477bfbf292d15c4a5742627091 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Sun, 23 Jun 2019 03:03:41 -0400 Subject: split notes tab added new HTMLEditor that triggers an editingFinished() on focus our, used by notes tab --- src/modinfodialog.cpp | 14 +------------- src/modinfodialog.ui | 17 +++++++++++------ src/modinfodialognexus.cpp | 2 -- src/modinfodialogtab.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/modinfodialogtab.h | 16 ++++++++++++++++ src/texteditor.cpp | 10 ++++++++++ src/texteditor.h | 17 +++++++++++++++++ 7 files changed, 94 insertions(+), 21 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 30110d14..b78f4515 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -19,7 +19,6 @@ along with Mod Organizer. If not, see . #include "modinfodialog.h" #include "ui_modinfodialog.h" -#include "descriptionpage.h" #include "mainwindow.h" #include "modidlineedit.h" @@ -173,9 +172,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo m_RootPath = modInfo->absolutePath(); - ui->commentsEdit->setText(modInfo->comments()); - ui->notesEdit->setText(modInfo->notes()); - //TODO: No easy way to delegate links //ui->descriptionView->page()->acceptNavigationRequest(QWebEnginePage::DelegateAllLinks); @@ -238,14 +234,6 @@ ModInfoDialog::ModInfoDialog(ModInfo::Ptr modInfo, const DirectoryEntry *directo ModInfoDialog::~ModInfoDialog() { - m_ModInfo->setComments(ui->commentsEdit->text()); - - //Avoid saving html stump if notes field is empty. - if (ui->notesEdit->toPlainText().isEmpty()) - m_ModInfo->setNotes(ui->notesEdit->toPlainText()); - else - m_ModInfo->setNotes(ui->notesEdit->toHtml()); - delete ui; } @@ -264,7 +252,7 @@ std::vector> ModInfoDialog::createTabs() { return createTabsImpl< TextFilesTab, IniFilesTab, ImagesTab, ESPsTab, - ConflictsTab, CategoriesTab, NexusTab>( + ConflictsTab, CategoriesTab, NexusTab, NotesTab>( *m_OrganizerCore, *m_PluginContainer, this, ui); } diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 29a7400f..360ecc79 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -6,7 +6,7 @@ 0 0 - 790 + 735 534 @@ -20,7 +20,7 @@ QTabWidget::Rounded - 0 + 7 true @@ -180,7 +180,7 @@ 0 0 - 741 + 686 436 @@ -859,7 +859,7 @@ text-align: left; - + :/MO/gui/resources/internet-web-browser.png:/MO/gui/resources/internet-web-browser.png @@ -963,7 +963,7 @@ p, li { white-space: pre-wrap; } - + <!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"> @@ -1071,7 +1071,7 @@ p, li { white-space: pre-wrap; } - + Enter notes about the mod here. These can be viewed in the mod list by hovering over the notes column or the flags column. @@ -1210,6 +1210,11 @@ p, li { white-space: pre-wrap; } QPlainTextEdit
texteditor.h
+ + HTMLEditor + QTextEdit +
texteditor.h
+
diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp index 753d43de..55b55439 100644 --- a/src/modinfodialognexus.cpp +++ b/src/modinfodialognexus.cpp @@ -248,8 +248,6 @@ void NexusTab::refreshData(int modID) } else { onModChanged(); } - - //MessageDialog::showMessage(tr("Info requested, please wait"), this); } bool NexusTab::tryRefreshData(int modID) diff --git a/src/modinfodialogtab.cpp b/src/modinfodialogtab.cpp index ae0de5e8..b59f4dcc 100644 --- a/src/modinfodialogtab.cpp +++ b/src/modinfodialogtab.cpp @@ -1,4 +1,6 @@ #include "modinfodialogtab.h" +#include "ui_modinfodialog.h" +#include "texteditor.h" ModInfoDialogTab::ModInfoDialogTab( OrganizerCore& oc, PluginContainer& plugin, @@ -73,3 +75,40 @@ void ModInfoDialogTab::emitModOpen(QString name) { emit modOpen(name); } + + +NotesTab::NotesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui) + : ModInfoDialogTab(oc, plugin, parent, ui) +{ + connect(ui->commentsEdit, &QLineEdit::editingFinished, [&]{ onComments(); }); + connect(ui->notesEdit, &HTMLEditor::editingFinished, [&]{ onNotes(); }); +} + +void NotesTab::clear() +{ + ui->commentsEdit->clear(); + ui->notesEdit->clear(); +} + +void NotesTab::update() +{ + ui->commentsEdit->setText(mod()->comments()); + ui->notesEdit->setText(mod()->notes()); +} + +void NotesTab::onComments() +{ + mod()->setComments(ui->commentsEdit->text()); +} + +void NotesTab::onNotes() +{ + // Avoid saving html stub if notes field is empty. + if (ui->notesEdit->toPlainText().isEmpty()) { + mod()->setNotes({}); + } else { + mod()->setNotes(ui->notesEdit->toHtml()); + } +} diff --git a/src/modinfodialogtab.h b/src/modinfodialogtab.h index dd851b31..60371954 100644 --- a/src/modinfodialogtab.h +++ b/src/modinfodialogtab.h @@ -60,4 +60,20 @@ private: MOShared::FilesOrigin* m_origin; }; + +class NotesTab : public ModInfoDialogTab +{ +public: + NotesTab( + OrganizerCore& oc, PluginContainer& plugin, + QWidget* parent, Ui::ModInfoDialog* ui); + + void clear() override; + void update() override; + +private: + void onComments(); + void onNotes(); +}; + #endif // MODINFODIALOGTAB_H diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 99490b22..6c1685da 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -458,3 +458,13 @@ void TextEditorToolbar::onWordWrap(bool b) { m_wordWrap->setChecked(b); } + + +void HTMLEditor::focusOutEvent(QFocusEvent* e) +{ + if (document() && document()->isModified()) { + emit editingFinished(); + } + + QTextEdit::focusInEvent(e); +} diff --git a/src/texteditor.h b/src/texteditor.h index eef5ca52..f3031731 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -137,4 +137,21 @@ private: void paintLineNumbers(QPaintEvent* e, const QColor& textColor); }; + +class HTMLEditor : public QTextEdit +{ + Q_OBJECT; + +public: + using QTextEdit::QTextEdit; + +signals: + void editingFinished(); + +protected: + void focusOutEvent(QFocusEvent* e); + +private: +}; + #endif // MO_TEXTEDITOR_H -- cgit v1.3.1 From cb56bf76fd8036895bda468a5ad9ef707dbefce9 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 25 Jun 2019 18:10:00 -0400 Subject: fixed text editors not clearing when switching mods ported typo fixes that applied to the mod info dialog --- src/modinfodialog.ui | 2 +- src/modinfodialogfiletree.cpp | 4 ++-- src/modinfodialogtextfiles.cpp | 1 + src/texteditor.cpp | 8 ++++++++ src/texteditor.h | 1 + 5 files changed, 13 insertions(+), 3 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 30ea9217..7a7d82da 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -426,7 +426,7 @@ Most mods do not have optional esps, so chances are good you are looking at an e ESPs in the data directory and thus visible to the game. - These are the mod files that are in the (virtual) data directory of your game and will thus be selectable in the esp list in the main window. + <html><head/><body><p>These are the mod files that are in the (virtual) data directory of your game and will thus be selectable in the esp list in the main window.</p></body></html> true diff --git a/src/modinfodialogfiletree.cpp b/src/modinfodialogfiletree.cpp index b57f6b5d..24faec5e 100644 --- a/src/modinfodialogfiletree.cpp +++ b/src/modinfodialogfiletree.cpp @@ -166,9 +166,9 @@ void FileTreeTab::onDelete() if (rows.count() == 1) { QString fileName = m_fs->fileName(rows[0]); - message = tr("Are sure you want to delete \"%1\"?").arg(fileName); + message = tr("Are you sure you want to delete \"%1\"?").arg(fileName); } else { - message = tr("Are sure you want to delete the selected files?"); + message = tr("Are you sure you want to delete the selected files?"); } if (QMessageBox::question(parentWidget(), tr("Confirm"), message) != QMessageBox::Yes) { diff --git a/src/modinfodialogtextfiles.cpp b/src/modinfodialogtextfiles.cpp index e3d00049..5b035c53 100644 --- a/src/modinfodialogtextfiles.cpp +++ b/src/modinfodialogtextfiles.cpp @@ -185,6 +185,7 @@ void GenericFilesTab::onSelection( void GenericFilesTab::select(const QModelIndex& index) { if (!index.isValid()) { + m_editor->clear(); m_editor->setEnabled(false); return; } diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 6c1685da..ee36c104 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -57,6 +57,14 @@ void TextEditor::setDefaultStyle() setHighlightBackgroundColor(backgroundColor); } +void TextEditor::clear() +{ + m_filename.clear(); + m_encoding.clear(); + setPlainText(""); + dirty(false); +} + bool TextEditor::load(const QString& filename) { m_filename = filename; diff --git a/src/texteditor.h b/src/texteditor.h index f3031731..775565f2 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -91,6 +91,7 @@ public: void setupToolbar(); + void clear(); bool load(const QString& filename); bool save(); -- cgit v1.3.1 From cac0fb710c48fa55c6e7303485adf9f4f3364682 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 25 Jun 2019 18:54:47 -0400 Subject: added explore button to editors fixed save button on editor being enabled with empty documents added ctrl+s always show vertical scrollbar in thumbnails, fixes nonstop relayouts when the height is just right and the scrollbar flickers on and off --- src/modinfodialog.ui | 6 ++++++ src/texteditor.cpp | 61 ++++++++++++++++++++++++++++++++++++++++++++++------ src/texteditor.h | 6 ++++++ 3 files changed, 66 insertions(+), 7 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 7a7d82da..56c97c34 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -168,6 +168,9 @@ Qt::Horizontal + + false + @@ -184,6 +187,9 @@ + + Qt::ScrollBarAlwaysOn + diff --git a/src/texteditor.cpp b/src/texteditor.cpp index ee36c104..9bbe3ddd 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -5,7 +5,7 @@ TextEditor::TextEditor(QWidget* parent) : QPlainTextEdit(parent), m_toolbar(nullptr), m_lineNumbers(nullptr), m_highlighter(nullptr), - m_dirty(false) + m_dirty(false), m_loading(false) { m_toolbar = new TextEditorToolbar(*this); m_lineNumbers = new TextEditorLineNumbers(*this); @@ -59,17 +59,25 @@ void TextEditor::setDefaultStyle() void TextEditor::clear() { + QScopedValueRollback loading(m_loading, true); + m_filename.clear(); m_encoding.clear(); setPlainText(""); dirty(false); + document()->setModified(false); + + emit loaded(""); } bool TextEditor::load(const QString& filename) { - m_filename = filename; clear(); + QScopedValueRollback loading(m_loading, true); + + m_filename = filename; + const QString s = MOBase::readFileText(filename, &m_encoding); setPlainText(s); @@ -81,6 +89,8 @@ bool TextEditor::load(const QString& filename) onModified(false); } + emit loaded(m_filename); + return true; } @@ -180,8 +190,21 @@ void TextEditor::setHighlightBackgroundColor(const QColor& c) update(); } +void TextEditor::explore() +{ + if (m_filename.isEmpty()) { + return; + } + + MOBase::shell::ExploreFile(m_filename); +} + void TextEditor::onModified(bool b) { + if (m_loading) { + return; + } + dirty(b); emit modified(b); } @@ -431,15 +454,27 @@ void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) } -TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : - m_editor(editor), - m_save(new QAction(QIcon(":/MO/gui/save"), QObject::tr("&Save"))), - m_wordWrap(new QAction(QIcon(":/MO/gui/word-wrap"), QObject::tr("&Word wrap"))) +TextEditorToolbar::TextEditorToolbar(TextEditor& editor) + : m_editor(editor), m_save(nullptr), m_wordWrap(nullptr), m_explore(nullptr) { - QObject::connect(m_save, &QAction::triggered, [&]{ m_editor.save(); }); + m_save = new QAction( + QIcon(":/MO/gui/save"), QObject::tr("&Save"), &editor); + + m_save->setShortcutContext(Qt::WidgetWithChildrenShortcut); + m_save->setShortcut(Qt::CTRL + Qt::Key_S); + m_editor.addAction(m_save); + + m_wordWrap = new QAction( + QIcon(":/MO/gui/word-wrap"), QObject::tr("&Word wrap"), &editor); + + m_explore = new QAction( + QObject::tr("&Open in Explorer"), &editor); m_wordWrap->setCheckable(true); + + QObject::connect(m_save, &QAction::triggered, [&]{ m_editor.save(); }); QObject::connect(m_wordWrap, &QAction::triggered, [&]{ m_editor.toggleWordWrap(); }); + QObject::connect(m_explore, &QAction::triggered, [&]{ m_editor.explore(); }); auto* layout = new QHBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); @@ -453,8 +488,13 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : b->setDefaultAction(m_wordWrap); layout->addWidget(b); + b = new QToolButton; + b->setDefaultAction(m_explore); + layout->addWidget(b); + QObject::connect(&m_editor, &TextEditor::modified, [&](bool b){ onTextModified(b); }); QObject::connect(&m_editor, &TextEditor::wordWrapChanged, [&](bool b){ onWordWrap(b); }); + QObject::connect(&m_editor, &TextEditor::loaded, [&](QString f){ onLoaded(f); }); } void TextEditorToolbar::onTextModified(bool b) @@ -467,6 +507,13 @@ void TextEditorToolbar::onWordWrap(bool b) m_wordWrap->setChecked(b); } +void TextEditorToolbar::onLoaded(const QString& s) +{ + const auto hasDoc = !s.isEmpty(); + + m_explore->setEnabled(hasDoc); + m_wordWrap->setEnabled(hasDoc); +} void HTMLEditor::focusOutEvent(QFocusEvent* e) { diff --git a/src/texteditor.h b/src/texteditor.h index 775565f2..798222a3 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -16,9 +16,11 @@ private: TextEditor& m_editor; QAction* m_save; QAction* m_wordWrap; + QAction* m_explore; void onTextModified(bool b); void onWordWrap(bool b); + void onLoaded(const QString& s); }; @@ -112,7 +114,10 @@ public: QColor highlightBackgroundColor() const; void setHighlightBackgroundColor(const QColor& c); + void explore(); + signals: + void loaded(QString filename); void modified(bool b); void wordWrapChanged(bool b); @@ -127,6 +132,7 @@ private: QString m_filename; QString m_encoding; bool m_dirty; + bool m_loading; void setDefaultStyle(); void onModified(bool b); -- cgit v1.3.1 From c90a822444da5842a12786dc923b2a481850608f Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Thu, 27 Jun 2019 10:57:27 -0400 Subject: added path to editor toolbar moved url to top in nexus tab and made it readonly --- src/modinfodialog.ui | 67 +++++++++++++++++++++++++++++++--------------- src/modinfodialognexus.cpp | 11 -------- src/modinfodialognexus.h | 1 - src/texteditor.cpp | 18 +++++++++---- src/texteditor.h | 1 + 5 files changed, 60 insertions(+), 38 deletions(-) (limited to 'src/texteditor.h') diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 01d70d73..4de65e95 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -887,7 +887,7 @@ text-align: left; - + @@ -996,19 +996,58 @@ p, li { white-space: pre-wrap; } - - - 150 - 16777215 - - 32 + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + URL + + + + + + + true + + + + + + @@ -1054,20 +1093,6 @@ p, li { white-space: pre-wrap; } - - - - - - URL - - - - - - - - diff --git a/src/modinfodialognexus.cpp b/src/modinfodialognexus.cpp index adf79060..e1fbe352 100644 --- a/src/modinfodialognexus.cpp +++ b/src/modinfodialognexus.cpp @@ -24,7 +24,6 @@ NexusTab::NexusTab( connect(ui->modID, &QLineEdit::editingFinished, [&]{ onModIDChanged(); }); connect(ui->version, &QLineEdit::editingFinished, [&]{ onVersionChanged(); }); connect(ui->openInBrowser, &QToolButton::clicked, [&]{ onOpenLink(); }); - connect(ui->url, &QLineEdit::editingFinished, [&]{ onUrlChanged(); }); connect(ui->endorse, &QToolButton::clicked, [&]{ onEndorse(); }); connect(ui->refresh, &QToolButton::clicked, [&]{ onRefreshBrowser(); }); @@ -242,16 +241,6 @@ void NexusTab::onVersionChanged() updateVersionColor(); } -void NexusTab::onUrlChanged() -{ - if (m_loading) { - return; - } - - mod()->setURL(ui->url->text()); - mod()->setLastNexusQuery(QDateTime::fromSecsSinceEpoch(0)); -} - void NexusTab::onOpenLink() { const int modID = mod()->getNexusID(); diff --git a/src/modinfodialognexus.h b/src/modinfodialognexus.h index 92330704..8528f0af 100644 --- a/src/modinfodialognexus.h +++ b/src/modinfodialognexus.h @@ -64,7 +64,6 @@ private: void onVersionChanged(); void onRefreshBrowser(); void onEndorse(); - void onUrlChanged(); }; #endif // MODINFODIALOGNEXUS_H diff --git a/src/texteditor.cpp b/src/texteditor.cpp index 9bbe3ddd..130cd76f 100644 --- a/src/texteditor.cpp +++ b/src/texteditor.cpp @@ -454,8 +454,9 @@ void TextEditorLineNumbers::updateArea(const QRect &rect, int dy) } -TextEditorToolbar::TextEditorToolbar(TextEditor& editor) - : m_editor(editor), m_save(nullptr), m_wordWrap(nullptr), m_explore(nullptr) +TextEditorToolbar::TextEditorToolbar(TextEditor& editor) : + m_editor(editor), m_save(nullptr), m_wordWrap(nullptr), m_explore(nullptr), + m_path(nullptr) { m_save = new QAction( QIcon(":/MO/gui/save"), QObject::tr("&Save"), &editor); @@ -467,10 +468,13 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) m_wordWrap = new QAction( QIcon(":/MO/gui/word-wrap"), QObject::tr("&Word wrap"), &editor); + m_wordWrap->setCheckable(true); + m_explore = new QAction( QObject::tr("&Open in Explorer"), &editor); - m_wordWrap->setCheckable(true); + m_path = new QLineEdit; + m_path->setReadOnly(true); QObject::connect(m_save, &QAction::triggered, [&]{ m_editor.save(); }); QObject::connect(m_wordWrap, &QAction::triggered, [&]{ m_editor.toggleWordWrap(); }); @@ -492,6 +496,8 @@ TextEditorToolbar::TextEditorToolbar(TextEditor& editor) b->setDefaultAction(m_explore); layout->addWidget(b); + layout->addWidget(m_path); + QObject::connect(&m_editor, &TextEditor::modified, [&](bool b){ onTextModified(b); }); QObject::connect(&m_editor, &TextEditor::wordWrapChanged, [&](bool b){ onWordWrap(b); }); QObject::connect(&m_editor, &TextEditor::loaded, [&](QString f){ onLoaded(f); }); @@ -507,12 +513,14 @@ void TextEditorToolbar::onWordWrap(bool b) m_wordWrap->setChecked(b); } -void TextEditorToolbar::onLoaded(const QString& s) +void TextEditorToolbar::onLoaded(const QString& path) { - const auto hasDoc = !s.isEmpty(); + const auto hasDoc = !path.isEmpty(); m_explore->setEnabled(hasDoc); m_wordWrap->setEnabled(hasDoc); + m_path->setEnabled(hasDoc); + m_path->setText(path); } void HTMLEditor::focusOutEvent(QFocusEvent* e) diff --git a/src/texteditor.h b/src/texteditor.h index 798222a3..dc53f1c4 100644 --- a/src/texteditor.h +++ b/src/texteditor.h @@ -17,6 +17,7 @@ private: QAction* m_save; QAction* m_wordWrap; QAction* m_explore; + QLineEdit* m_path; void onTextModified(bool b); void onWordWrap(bool b); -- cgit v1.3.1