diff --git a/tools/lammps-gui/.clang-format b/tools/lammps-gui/.clang-format new file mode 100644 index 0000000000..4e4dd24ed7 --- /dev/null +++ b/tools/lammps-gui/.clang-format @@ -0,0 +1,23 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AccessModifierOffset: -4 +AlignConsecutiveAssignments: true +AlignEscapedNewlines: Left +AllowShortFunctionsOnASingleLine: Inline +AllowShortLambdasOnASingleLine: None +AllowShortIfStatementsOnASingleLine: WithoutElse +BraceWrapping: + AfterFunction: true +BreakBeforeBraces: Custom +BreakInheritanceList: AfterColon +BreakConstructorInitializers: AfterColon +ColumnLimit: 80 +IndentCaseLabels: true +IndentWidth: 4 +ObjCBlockIndentWidth: 4 +PenaltyBreakAssignment: 4 +Standard: Cpp11 +TabWidth: 4 +UseTab: Never +... diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 85c07abc57..1e724671a1 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -52,10 +52,13 @@ find_package(QT NAMES Qt5 REQUIRED COMPONENTS Widgets) find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets) set(PROJECT_SOURCES - main.cpp - lammpsgui.cpp - lammpsgui.h - lammpsgui.ui + main.cpp + codeeditor.cpp + codeeditor.h + linenumberarea.h + lammpsgui.cpp + lammpsgui.h + lammpsgui.ui ) if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) diff --git a/tools/lammps-gui/codeeditor.cpp b/tools/lammps-gui/codeeditor.cpp new file mode 100644 index 0000000000..36a56ec54f --- /dev/null +++ b/tools/lammps-gui/codeeditor.cpp @@ -0,0 +1,102 @@ +#include "codeeditor.h" +#include "linenumberarea.h" + +#include +#include + +CodeEditor::CodeEditor(QWidget *parent) : QPlainTextEdit(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) +{ + 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 *e) +{ + QPlainTextEdit::resizeEvent(e); + + 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) +{ + QPainter painter(lineNumberArea); + painter.fillRect(event->rect(), Qt::lightGray); + QTextBlock block = firstVisibleBlock(); + int blockNumber = block.blockNumber(); + int top = + qRound(blockBoundingGeometry(block).translated(contentOffset()).top()); + int bottom = top + qRound(blockBoundingRect(block).height()); + 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); + } + + block = block.next(); + top = bottom; + bottom = top + qRound(blockBoundingRect(block).height()); + ++blockNumber; + } +} diff --git a/tools/lammps-gui/codeeditor.h b/tools/lammps-gui/codeeditor.h new file mode 100644 index 0000000000..745a09ac10 --- /dev/null +++ b/tools/lammps-gui/codeeditor.h @@ -0,0 +1,40 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifndef CODEEDITOR_H +#define CODEEDITOR_H + +#include + +class CodeEditor : public QPlainTextEdit { + Q_OBJECT + +public: + CodeEditor(QWidget *parent = nullptr); + + void lineNumberAreaPaintEvent(QPaintEvent *event); + int lineNumberAreaWidth(); + +protected: + void resizeEvent(QResizeEvent *event) override; + +private slots: + void updateLineNumberAreaWidth(int newBlockCount); + void highlightCurrentLine(); + void updateLineNumberArea(const QRect &rect, int dy); + +private: + QWidget *lineNumberArea; +}; + +#endif diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index b0fbd74b68..63900b4e9c 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -1,25 +1,26 @@ #include "lammpsgui.h" -#include "./ui_lammpsgui.h" -#include "library.h" +#include "ui_lammpsgui.h" -#include -#include #include #include -#include #include +#include +#include -LammpsGui::LammpsGui(QWidget *parent) - : QMainWindow(parent), ui(new Ui::LammpsGui), lammps_handle(nullptr) +#include "library.h" + +LammpsGui::LammpsGui(QWidget *parent, const char *filename) : + QMainWindow(parent), ui(new Ui::LammpsGui), lammps_handle(nullptr) { ui->setupUi(this); this->setCentralWidget(ui->textEdit); current_file.clear(); - current_line = 0; + + QFont text_font; text_font.setFamily("monospace"); text_font.setFixedPitch(true); text_font.setStyleHint(QFont::TypeWriter); - ui->textEdit->setCurrentFont(text_font); + ui->textEdit->document()->setDefaultFont(text_font); connect(ui->actionNew, &QAction::triggered, this, &LammpsGui::new_document); connect(ui->actionOpen, &QAction::triggered, this, &LammpsGui::open); @@ -32,15 +33,23 @@ LammpsGui::LammpsGui(QWidget *parent) connect(ui->actionUndo, &QAction::triggered, this, &LammpsGui::undo); connect(ui->actionRedo, &QAction::triggered, this, &LammpsGui::redo); connect(ui->actionClear, &QAction::triggered, this, &LammpsGui::clear); - connect(ui->actionRun_Buffer, &QAction::triggered, this, &LammpsGui::run_buffer); - connect(ui->actionExecute_Line, &QAction::triggered, this, &LammpsGui::run_line); -// connect(ui->actionAbout, &QAction::triggered, this, &LammpsGui::about); + connect(ui->actionRun_Buffer, &QAction::triggered, this, + &LammpsGui::run_buffer); + connect(ui->actionExecute_Line, &QAction::triggered, this, + &LammpsGui::run_line); + // connect(ui->actionAbout, &QAction::triggered, this, + // &LammpsGui::about); #if !QT_CONFIG(clipboard) ui->actionCut->setEnabled(false); ui->actionCopy->setEnabled(false); ui->actionPaste->setEnabled(false); #endif + + if (filename) + open_file(filename); + else + setWindowTitle(QString("LAMMPS-GUI - *unknown*")); } LammpsGui::~LammpsGui() @@ -50,27 +59,33 @@ LammpsGui::~LammpsGui() void LammpsGui::new_document() { - current_file.clear(); - current_line = 0; - ui->textEdit->setText(QString()); - if (lammps_handle) lammps_close(lammps_handle); - lammps_handle = nullptr; + current_file.clear(); + ui->textEdit->document()->setPlainText(QString()); + if (lammps_handle) lammps_close(lammps_handle); + lammps_handle = nullptr; + setWindowTitle(QString("LAMMPS-GUI - *unknown*")); } void LammpsGui::open() { QString fileName = QFileDialog::getOpenFileName(this, "Open the file"); + open_file(fileName); +} + +void LammpsGui::open_file(const QString &fileName) +{ QFile file(fileName); current_file = fileName; - current_line = 0; if (!file.open(QIODevice::ReadOnly | QFile::Text)) { - QMessageBox::warning(this, "Warning", "Cannot open file: " + file.errorString()); + QMessageBox::warning(this, "Warning", + "Cannot open file: " + file.errorString()); return; } - setWindowTitle(fileName); + setWindowTitle(QString("LAMMPS-GUI - " + fileName)); QTextStream in(&file); QString text = in.readAll(); - ui->textEdit->setText(text); + ui->textEdit->document()->setPlainText(text); + ui->textEdit->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor); file.close(); } @@ -79,17 +94,18 @@ void LammpsGui::save() QString fileName; // If we don't have a filename from before, get one. if (current_file.isEmpty()) { - fileName = QFileDialog::getSaveFileName(this, "Save"); + fileName = QFileDialog::getSaveFileName(this, "Save"); current_file = fileName; } else { fileName = current_file; } QFile file(fileName); if (!file.open(QIODevice::WriteOnly | QFile::Text)) { - QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); + QMessageBox::warning(this, "Warning", + "Cannot save file: " + file.errorString()); return; } - setWindowTitle(fileName); + setWindowTitle(QString("LAMMPS-GUI - " + fileName)); QTextStream out(&file); QString text = ui->textEdit->toPlainText(); out << text; @@ -102,11 +118,12 @@ void LammpsGui::save_as() QFile file(fileName); if (!file.open(QFile::WriteOnly | QFile::Text)) { - QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString()); + QMessageBox::warning(this, "Warning", + "Cannot save file: " + file.errorString()); return; } current_file = fileName; - setWindowTitle(fileName); + setWindowTitle(QString("LAMMPS-GUI - " + fileName)); QTextStream out(&file); QString text = ui->textEdit->toPlainText(); out << text; @@ -115,13 +132,13 @@ void LammpsGui::save_as() void LammpsGui::quit() { - if (lammps_handle) { - lammps_close(lammps_handle); - lammps_mpi_finalize(); - lammps_kokkos_finalize(); - lammps_python_finalize(); - } - QCoreApplication::quit(); + if (lammps_handle) { + lammps_close(lammps_handle); + lammps_mpi_finalize(); + lammps_kokkos_finalize(); + lammps_python_finalize(); + } + QCoreApplication::quit(); } void LammpsGui::copy() @@ -147,7 +164,7 @@ void LammpsGui::paste() void LammpsGui::undo() { - ui->textEdit->undo(); + ui->textEdit->undo(); } void LammpsGui::redo() @@ -157,27 +174,39 @@ void LammpsGui::redo() void LammpsGui::run_buffer() { - clear(); - if (!lammps_handle) lammps_handle = lammps_open_no_mpi(0, nullptr, nullptr); - if (!lammps_handle) return; - std::string buffer = ui->textEdit->toPlainText().toStdString(); - lammps_commands_string(lammps_handle, buffer.c_str()); + char *args[] = {(char *)"LAMMPS GUI", (char *)"-log", (char *)"none"}; + int nargs = sizeof(args) / sizeof(char *); + + clear(); + if (!lammps_handle) + lammps_handle = lammps_open_no_mpi(nargs, args, nullptr); + if (!lammps_handle) return; + std::string buffer = ui->textEdit->toPlainText().toStdString(); + lammps_commands_string(lammps_handle, buffer.c_str()); } void LammpsGui::run_line() { - // dummy + char *args[] = {(char *)"LAMMPS GUI", (char *)"-log", (char *)"none"}; + int nargs = sizeof(args) / sizeof(char *); + + if (!lammps_handle) + lammps_handle = lammps_open_no_mpi(nargs, args, nullptr); + if (!lammps_handle) return; + + // std::string buffer = ui->textEdit->toPlainText().toStdString(); + // lammps_commands_string(lammps_handle, buffer.c_str()); } void LammpsGui::clear() { - if (lammps_handle) { - lammps_command(lammps_handle, "clear"); - current_line = 0; - } + if (lammps_handle) { + lammps_command(lammps_handle, "clear"); + } + ui->textEdit->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor); } void LammpsGui::about() { - // dummy + // dummy } diff --git a/tools/lammps-gui/lammpsgui.h b/tools/lammps-gui/lammpsgui.h index d56a981ddf..be9c6e900f 100644 --- a/tools/lammps-gui/lammpsgui.h +++ b/tools/lammps-gui/lammpsgui.h @@ -1,22 +1,38 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + #ifndef LAMMPSGUI_H #define LAMMPSGUI_H #include -#include #include QT_BEGIN_NAMESPACE -namespace Ui { class LammpsGui; } +namespace Ui { +class LammpsGui; +} QT_END_NAMESPACE -class LammpsGui : public QMainWindow -{ +class LammpsGui : public QMainWindow { Q_OBJECT public: - LammpsGui(QWidget *parent = nullptr); + LammpsGui(QWidget *parent = nullptr, const char *filename = nullptr); ~LammpsGui(); +protected: + void open_file(const QString &filename); + private slots: void new_document(); void open(); @@ -35,9 +51,9 @@ private slots: private: Ui::LammpsGui *ui; + QString current_file; - QFont text_font; - int current_line; void *lammps_handle; }; + #endif // LAMMPSGUI_H diff --git a/tools/lammps-gui/lammpsgui.ui b/tools/lammps-gui/lammpsgui.ui index 6ea0351cce..1aa560e979 100644 --- a/tools/lammps-gui/lammpsgui.ui +++ b/tools/lammps-gui/lammpsgui.ui @@ -25,7 +25,7 @@ - + diff --git a/tools/lammps-gui/linenumberarea.cpp b/tools/lammps-gui/linenumberarea.cpp new file mode 100644 index 0000000000..38c45bb493 --- /dev/null +++ b/tools/lammps-gui/linenumberarea.cpp @@ -0,0 +1,58 @@ +#include "codeeditor.h" + +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) +{ + 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 *e) +{ + QTextEdit::resizeEvent(e); + + 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); +} diff --git a/tools/lammps-gui/linenumberarea.h b/tools/lammps-gui/linenumberarea.h new file mode 100644 index 0000000000..2af6e6f4bb --- /dev/null +++ b/tools/lammps-gui/linenumberarea.h @@ -0,0 +1,38 @@ +/* -*- c++ -*- ---------------------------------------------------------- + LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator + https://www.lammps.org/, Sandia National Laboratories + LAMMPS development team: developers@lammps.org + + Copyright (2003) Sandia Corporation. Under the terms of Contract + DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains + certain rights in this software. This software is distributed under + the GNU General Public License. + + See the README file in the top-level LAMMPS directory. +------------------------------------------------------------------------- */ + +#ifndef LINENUMBERAREA_H +#define LINENUMBERAREA_H + +#include "codeeditor.h" +#include + +class LineNumberArea : public QWidget { +public: + 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 diff --git a/tools/lammps-gui/main.cpp b/tools/lammps-gui/main.cpp index 7ee8f9150f..7e13017eaf 100644 --- a/tools/lammps-gui/main.cpp +++ b/tools/lammps-gui/main.cpp @@ -5,7 +5,11 @@ int main(int argc, char *argv[]) { QApplication a(argc, argv); - LammpsGui w; + + const char *infile = nullptr; + if (argc > 1) infile = argv[1]; + + LammpsGui w(nullptr, infile); w.show(); return a.exec(); }