diff --git a/tools/lammps-gui/CMakeLists.txt b/tools/lammps-gui/CMakeLists.txt index 057d686b12..3c49c4cd8a 100644 --- a/tools/lammps-gui/CMakeLists.txt +++ b/tools/lammps-gui/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.16) -project(lammps-gui VERSION 1.6.11 LANGUAGES CXX) +project(lammps-gui VERSION 1.6.12 LANGUAGES CXX) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOMOC ON) diff --git a/tools/lammps-gui/lammps-gui.appdata.xml b/tools/lammps-gui/lammps-gui.appdata.xml index 1f74fc479c..a40f56d3d0 100644 --- a/tools/lammps-gui/lammps-gui.appdata.xml +++ b/tools/lammps-gui/lammps-gui.appdata.xml @@ -54,11 +54,17 @@ + + + Update Tutorial menu entries to cover all 8 tutorials + Highlight warnings and error messages in Output window + + - move cursor to end of log buffer before inserting new text - remove empirical filter to remove outliers from corrupted data - change tutorial download URL to tutorial website + Move cursor to end of log buffer before inserting new text + Remove empirical filter to remove outliers from corrupted data + Change tutorial download URL to tutorial website diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index fb38b6fc92..04015ebad4 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -217,6 +217,12 @@ LammpsGui::LammpsGui(QWidget *parent, const QString &filename) : connect(ui->actionLAMMPS_Tutorial, &QAction::triggered, this, &LammpsGui::tutorial_web); connect(ui->actionTutorial1, &QAction::triggered, this, &LammpsGui::start_tutorial1); connect(ui->actionTutorial2, &QAction::triggered, this, &LammpsGui::start_tutorial2); + connect(ui->actionTutorial3, &QAction::triggered, this, &LammpsGui::start_tutorial3); + connect(ui->actionTutorial4, &QAction::triggered, this, &LammpsGui::start_tutorial4); + connect(ui->actionTutorial5, &QAction::triggered, this, &LammpsGui::start_tutorial5); + connect(ui->actionTutorial6, &QAction::triggered, this, &LammpsGui::start_tutorial6); + connect(ui->actionTutorial7, &QAction::triggered, this, &LammpsGui::start_tutorial7); + connect(ui->actionTutorial8, &QAction::triggered, this, &LammpsGui::start_tutorial8); connect(ui->actionAbout_LAMMPS_GUI, &QAction::triggered, this, &LammpsGui::about); connect(ui->action_Help, &QAction::triggered, this, &LammpsGui::help); connect(ui->actionLAMMPS_GUI_Howto, &QAction::triggered, this, &LammpsGui::howto); @@ -438,9 +444,7 @@ void LammpsGui::open_recent() void LammpsGui::get_directory() { if (wizard) { - // figure out which wizard we are following - auto *line = wizard->findChild("t1_directory"); - if (!line) line = wizard->findChild("t2_directory"); + auto *line = wizard->findChild("t_directory"); if (line) { auto curdir = line->text(); QFileDialog dialog(this, "Choose Directory for Tutorial Files", curdir); @@ -1560,287 +1564,313 @@ void LammpsGui::tutorial_web() QDesktopServices::openUrl(QUrl("https://lammpstutorials.github.io/")); } +QWizardPage *LammpsGui::tutorial_intro(const int ntutorial) +{ + auto *page = new QWizardPage; + page->setTitle(QString("Getting Started With Tutorial %1").arg(ntutorial)); + page->setPixmap(QWizard::WatermarkPixmap, + QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial))); + + // XXX TODO: update URL to published tutorial DOI + auto *label = new QLabel( + QString("

This wizard will help you to select and populate a folder with materials " + "required to work through tutorial %1 from the LAMMPS tutorials article by " + "Simon Gravelle, Jake Gissinger, and Axel Kohlmeyer.

\nThe materials for this " + "tutorial are downloaded from:
github.com/" + "lammpstutorials/lammpstutorials-article


\n
\n

Click on the \"Next\" button to begin.

") + .arg(ntutorial)); + label->setWordWrap(true); + + auto *layout = new QVBoxLayout; + layout->addWidget(label); + page->setLayout(layout); + return page; +} + +QWizardPage *LammpsGui::tutorial_info(const int ntutorial, const QString &infotext) +{ + auto *page = new QWizardPage; + page->setTitle(QString("Contents of Tutorial %1").arg(ntutorial)); + page->setPixmap(QWizard::WatermarkPixmap, + QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial))); + + auto *label = new QLabel(infotext); + label->setWordWrap(true); + + auto *layout = new QVBoxLayout; + layout->addWidget(label); + page->setLayout(layout); + return page; +} + +QWizardPage *LammpsGui::tutorial_directory(const int ntutorial) +{ + auto *page = new QWizardPage; + page->setTitle(QString("Select Directory for Tutorial %1").arg(ntutorial)); + page->setPixmap(QWizard::WatermarkPixmap, + QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial))); + + auto *frame = new QFrame; + auto *label = new QLabel( + QString("

Select a directory to store the files for tutorial %1. The directory will be " + "created if necessary and LAMMPS-GUI will download the files required for the " + "tutorial.

\n

If selected, an existing directory may be " + "cleared.

\n

Also, available files of the tutorial solution may be downloaded " + "to a folder \"solution\", if requested.

\n
\n") + .arg(ntutorial)); + label->setWordWrap(true); + + auto *dirlayout = new QHBoxLayout; + auto *directory = new QLineEdit; + + // if we are already in a tutorial folder, stay there or pick folder in same parent dir + bool haveDir = false; + for (int i = 1; i < 99; ++i) { + if (current_dir.endsWith(QString("tutorial%1").arg(i))) { + if (i > 9) { // We assume there are no more than 99 tutorials + current_dir.chop(2); + } else { + current_dir.chop(1); + } + current_dir.append(QString::number(ntutorial)); + haveDir = true; + } + } + + // if current dir is home, or application folder, switch to desktop path + if ((current_dir == QDir::homePath()) || current_dir.contains("AppData") || + current_dir.contains("Program Files")) { + current_dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); + } + if (!haveDir) current_dir.append(QString("/tutorial%1").arg(ntutorial)); + directory->setText(current_dir); + + auto *dirbutton = new QPushButton("&Choose"); + dirlayout->addWidget(directory); + dirlayout->addWidget(dirbutton); + directory->setObjectName("t_directory"); + connect(dirbutton, &QPushButton::released, this, &LammpsGui::get_directory); + + auto *grid = new QGridLayout; + auto *purgeval = new QCheckBox; + auto *solval = new QCheckBox; + auto *purgelabel = new QLabel("Remove existing files from directory"); + auto *sollabel = new QLabel("Download solutions"); + purgeval->setCheckState(Qt::Unchecked); + purgeval->setObjectName("t_dirpurge"); + solval->setCheckState(Qt::Unchecked); + solval->setObjectName("t_getsolution"); + grid->addWidget(purgeval, 0, 0, Qt::AlignVCenter); + grid->addWidget(purgelabel, 0, 1, Qt::AlignVCenter); + grid->addWidget(solval, 1, 0, Qt::AlignVCenter); + grid->addWidget(sollabel, 1, 1, Qt::AlignVCenter); + grid->setColumnStretch(0, 0); + grid->setColumnStretch(1, 100); + + auto *layout = new QVBoxLayout(frame); + layout->addWidget(label); + layout->addLayout(dirlayout); + layout->addLayout(grid); + + page->setLayout(layout); + return page; +} + +QWizardPage *LammpsGui::tutorial_finish(const int ntutorial) +{ + auto *page = new QWizardPage; + page->setTitle(QString("Start Tutorial %1").arg(ntutorial)); + page->setPixmap(QWizard::WatermarkPixmap, + QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial))); + auto *label = new QLabel(QString("

You are now ready to start tutorial " + "%1.

\n
\n

Click on " + "the \"Finish\" button to complete the setup.

") + .arg(ntutorial)); + label->setWordWrap(true); + + auto *layout = new QVBoxLayout; + layout->addWidget(label); + layout->setStretch(0, 100); + + page->setLayout(layout); + return page; +} + void LammpsGui::start_tutorial1() { if (wizard) delete wizard; - wizard = new Tutorial1Wizard; + wizard = new TutorialWizard(1); + const auto infotext = + QString("

In tutorial 1 you will learn about LAMMPS input files, their syntax and " + "structure, how to create and set up models and their interactions, how to run a " + "minimization and a molecular dynamics trajectory, how to plot thermodynamic data " + "and how to create visualizations of your system


\n

Click on the \"Next\" button to select a folder.

"); wizard->setFont(font()); - wizard->addPage(tutorial1_intro()); - wizard->addPage(tutorial1_info()); - wizard->addPage(tutorial1_directory()); - wizard->addPage(tutorial1_finish()); + wizard->addPage(tutorial_intro(1)); + wizard->addPage(tutorial_info(1, infotext)); + wizard->addPage(tutorial_directory(1)); + wizard->addPage(tutorial_finish(1)); wizard->setWindowTitle("Tutorial 1 Setup Wizard"); wizard->setWizardStyle(QWizard::ModernStyle); wizard->show(); } -QWizardPage *LammpsGui::tutorial1_intro() -{ - auto *page = new QWizardPage; - page->setTitle("Getting Started With Tutorial 1"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png")); - - // XXX TODO: update URL to published tutorial DOI - auto *label = - new QLabel("

This wizard will help you to select and populate a folder with " - "materials required to work through tutorial 1 from a fourthcoming " - "LAMMPS tutorial using LAMMPS-GUI by Simon Gravelle, Jake Gissinger, " - "and Axel Kohlmeyer.

\n" - "The work-in-progress materials for this tutorial are available at: " - "github.com/lammpstutorials/lammpstutorials-article


\n" - "
\n" - "

Click on the \"Next\" button to begin.

"); - label->setWordWrap(true); - - auto *layout = new QVBoxLayout; - layout->addWidget(label); - page->setLayout(layout); - return page; -} - -QWizardPage *LammpsGui::tutorial1_info() -{ - auto *page = new QWizardPage; - page->setTitle("Contents of Tutorial 1"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png")); - - auto *label = - new QLabel("

In tutorial 1 you will learn about LAMMPS input files, their syntax and " - " structure, how to create and set up models and their interactions, how to " - "run a minimization and a molecular dynamics trajectory, how to plot " - "thermodynamic data and how to create visualizations of your system

" - "
\n" - "

Click on the \"Next\" button to select a folder.

"); - label->setWordWrap(true); - - auto *layout = new QVBoxLayout; - layout->addWidget(label); - page->setLayout(layout); - return page; -} - -QWizardPage *LammpsGui::tutorial1_directory() -{ - auto *page = new QWizardPage; - page->setTitle("Select Directory for Tutorial 1"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png")); - - auto *frame = new QFrame; - auto *label = new QLabel( - "

Select a directory to store the files for tutorial 1. The directory will be " - "created if necessary and LAMMPS-GUI will download the files required for the " - "tutorial.

\n" - "

If selected, an existing directory may be cleared.

\n" - "

Also, available files of the tutorial solution may be downloaded to a " - "folder \"solution\", if requested.

\n" - "
\n"); - label->setWordWrap(true); - - auto *dirlayout = new QHBoxLayout; - auto *directory = new QLineEdit; - // if we are already in the tutorial folder, stay there - if (!current_dir.endsWith("tutorial1")) { - // if current dir is home, or application folder, switch to desktop path - if ((current_dir == QDir::homePath()) || current_dir.contains("AppData") || - current_dir.contains("Program Files")) { - current_dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - } - current_dir += "/tutorial1"; - } - directory->setText(current_dir); - - auto *dirbutton = new QPushButton("&Choose"); - dirlayout->addWidget(directory); - dirlayout->addWidget(dirbutton); - directory->setObjectName("t1_directory"); - connect(dirbutton, &QPushButton::released, this, &LammpsGui::get_directory); - - auto *grid = new QGridLayout; - auto *purgeval = new QCheckBox; - auto *solval = new QCheckBox; - auto *purgelabel = new QLabel("Remove existing files from directory"); - auto *sollabel = new QLabel("Download solutions"); - purgeval->setCheckState(Qt::Unchecked); - purgeval->setObjectName("t1_dirpurge"); - solval->setCheckState(Qt::Unchecked); - solval->setObjectName("t1_getsolution"); - grid->addWidget(purgeval, 0, 0, Qt::AlignVCenter); - grid->addWidget(purgelabel, 0, 1, Qt::AlignVCenter); - grid->addWidget(solval, 1, 0, Qt::AlignVCenter); - grid->addWidget(sollabel, 1, 1, Qt::AlignVCenter); - grid->setColumnStretch(0, 0); - grid->setColumnStretch(1, 100); - - auto *layout = new QVBoxLayout(frame); - layout->addWidget(label); - layout->addLayout(dirlayout); - layout->addLayout(grid); - - page->setLayout(layout); - return page; -} - -QWizardPage *LammpsGui::tutorial1_finish() -{ - auto *page = new QWizardPage; - page->setTitle("Start Tutorial 1"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png")); - - auto *label = new QLabel("

You are now ready to start tutorial 1.

\n" - "
\n" - "

Click on the \"Finish\" button to " - "complete the setup.

"); - label->setWordWrap(true); - - auto *layout = new QVBoxLayout; - layout->addWidget(label); - layout->setStretch(0, 100); - - page->setLayout(layout); - return page; -} - void LammpsGui::start_tutorial2() { if (wizard) delete wizard; - wizard = new Tutorial2Wizard; - wizard->addPage(tutorial2_intro()); - wizard->addPage(tutorial2_info()); - wizard->addPage(tutorial2_directory()); - wizard->addPage(tutorial2_finish()); + wizard = new TutorialWizard(2); + const auto infotext = + QString("

In tutorial 2 you will learn about setting up a simulation for a molecular " + "system with bonds. The target is to simulate a carbon nanotube with a " + "conventional molecular force field under growing strain and observe the response " + "to it. Since bonds are represented by a harmonic potential, they cannot break. " + "This is then compared to simulating the same system with a reactive force field " + "(AIREBO) where bonds may be broken and formed.


\n

Click on the \"Next\" button to select a folder.

"); + wizard->setFont(font()); + wizard->addPage(tutorial_intro(2)); + wizard->addPage(tutorial_info(2, infotext)); + wizard->addPage(tutorial_directory(2)); + wizard->addPage(tutorial_finish(2)); wizard->setWindowTitle("Tutorial 2 Setup Wizard"); wizard->setWizardStyle(QWizard::ModernStyle); wizard->show(); } -QWizardPage *LammpsGui::tutorial2_intro() +void LammpsGui::start_tutorial3() { - auto *page = new QWizardPage; - page->setTitle("Getting Started With Tutorial 2"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); + if (wizard) delete wizard; + wizard = new TutorialWizard(3); + const auto infotext = + QString("

In tutorial 3 you will learn about setting up a simulation for a molecular " + "system with bonds. The target is to simulate a carbon nanotube with a " + "conventional molecular force field under growing strain and observe the response " + "to it. Since bonds are represented by a harmonic potential, they cannot break. " + "This is then compared to simulating the same system with a reactive force field " + "(AIREBO) where bonds may be broken and formed.


\n

Click on the \"Next\" button to select a folder.

"); - // XXX TODO: update URL to published tutorial DOI - auto *label = - new QLabel("

This wizard will help you to select and populate a folder with " - "materials required to work through tutorial 2 from a fourthcoming " - "LAMMPS tutorial using LAMMPS-GUI by Simon Gravelle, Jake Gissinger, " - "and Axel Kohlmeyer.

\n" - "The work-in-progress materials for this tutorial are available at: " - "github.com/lammpstutorials/lammpstutorials-article


\n" - "
\n" - "

Click on the \"Next\" button to begin.

"); - label->setWordWrap(true); - - auto *layout = new QVBoxLayout; - layout->addWidget(label); - page->setLayout(layout); - return page; + wizard->setFont(font()); + wizard->addPage(tutorial_intro(3)); + wizard->addPage(tutorial_info(3, infotext)); + wizard->addPage(tutorial_directory(3)); + wizard->addPage(tutorial_finish(3)); + wizard->setWindowTitle("Tutorial 3 Setup Wizard"); + wizard->setWizardStyle(QWizard::ModernStyle); + wizard->show(); } -QWizardPage *LammpsGui::tutorial2_info() +void LammpsGui::start_tutorial4() { - auto *page = new QWizardPage; - page->setTitle("Contents of Tutorial 2"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); - - auto *label = - new QLabel("

In tutorial 2 you will learn about setting up a simulation for a molecular " - "system with bonds. The target is to simulate a carbon nanotube with a " - "conventional molecular force field under growing strain and observe the " - "response to it. Since bonds are represented by a harmonic potential, they " - "cannot break. This is then compared to simulating the same system with a " - "reactive force field (AIREBO) where bonds may be broken and formed.

" - "
\n" - "

Click on the \"Next\" button to select a folder.

"); - label->setWordWrap(true); - - auto *layout = new QVBoxLayout; - layout->addWidget(label); - page->setLayout(layout); - return page; + if (wizard) delete wizard; + wizard = new TutorialWizard(4); + const auto infotext = + QString("

In tutorial 4 you will learn about setting up a simulation for a molecular " + "system with bonds. The target is to simulate a carbon nanotube with a " + "conventional molecular force field under growing strain and observe the response " + "to it. Since bonds are represented by a harmonic potential, they cannot break. " + "This is then compared to simulating the same system with a reactive force field " + "(AIREBO) where bonds may be broken and formed.


\n

Click on the \"Next\" button to select a folder.

"); + wizard->setFont(font()); + wizard->addPage(tutorial_intro(4)); + wizard->addPage(tutorial_info(4, infotext)); + wizard->addPage(tutorial_directory(4)); + wizard->addPage(tutorial_finish(4)); + wizard->setWindowTitle("Tutorial 4 Setup Wizard"); + wizard->setWizardStyle(QWizard::ModernStyle); + wizard->show(); } -QWizardPage *LammpsGui::tutorial2_directory() +void LammpsGui::start_tutorial5() { - auto *page = new QWizardPage; - page->setTitle("Select Directory for Tutorial 2"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); - - auto *frame = new QFrame; - auto *label = new QLabel( - "

Select a directory to store the files for tutorial 2. The directory will be " - "created if necessary and LAMMPS-GUI will download the files required for the " - "tutorial.

\n" - "

If selected, an existing directory may be cleared.

\n" - "

Also, available files of the tutorial solution may be downloaded to a " - "folder \"solution\", if requested.

\n" - "
\n"); - label->setWordWrap(true); - - auto *dirlayout = new QHBoxLayout; - auto *directory = new QLineEdit; - // if we are already in the tutorial folder, stay there - if (!current_dir.endsWith("tutorial2")) { - // if current dir is home, or application folder, switch to desktop path - if ((current_dir == QDir::homePath()) || current_dir.contains("AppData") || - current_dir.contains("Program Files")) { - current_dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation); - } - current_dir += "/tutorial2"; - } - directory->setText(current_dir); - - auto *dirbutton = new QPushButton("&Choose"); - dirlayout->addWidget(directory); - dirlayout->addWidget(dirbutton); - directory->setObjectName("t2_directory"); - connect(dirbutton, &QPushButton::released, this, &LammpsGui::get_directory); - - auto *grid = new QGridLayout; - auto *purgeval = new QCheckBox; - auto *solval = new QCheckBox; - auto *purgelabel = new QLabel("Remove existing files from directory"); - auto *sollabel = new QLabel("Download solutions"); - purgeval->setCheckState(Qt::Unchecked); - purgeval->setObjectName("t2_dirpurge"); - solval->setCheckState(Qt::Unchecked); - solval->setObjectName("t2_getsolution"); - grid->addWidget(purgeval, 0, 0, Qt::AlignVCenter); - grid->addWidget(purgelabel, 0, 1, Qt::AlignVCenter); - grid->addWidget(solval, 1, 0, Qt::AlignVCenter); - grid->addWidget(sollabel, 1, 1, Qt::AlignVCenter); - grid->setColumnStretch(0, 0); - grid->setColumnStretch(1, 100); - - auto *layout = new QVBoxLayout(frame); - layout->addWidget(label); - layout->addLayout(dirlayout); - layout->addLayout(grid); - - page->setLayout(layout); - return page; + if (wizard) delete wizard; + wizard = new TutorialWizard(5); + const auto infotext = + QString("

In tutorial 5 you will learn about setting up a simulation for a molecular " + "system with bonds. The target is to simulate a carbon nanotube with a " + "conventional molecular force field under growing strain and observe the response " + "to it. Since bonds are represented by a harmonic potential, they cannot break. " + "This is then compared to simulating the same system with a reactive force field " + "(AIREBO) where bonds may be broken and formed.


\n

Click on the \"Next\" button to select a folder.

"); + wizard->setFont(font()); + wizard->addPage(tutorial_intro(5)); + wizard->addPage(tutorial_info(5, infotext)); + wizard->addPage(tutorial_directory(5)); + wizard->addPage(tutorial_finish(5)); + wizard->setWindowTitle("Tutorial 5 Setup Wizard"); + wizard->setWizardStyle(QWizard::ModernStyle); + wizard->show(); } -QWizardPage *LammpsGui::tutorial2_finish() +void LammpsGui::start_tutorial6() { - auto *page = new QWizardPage; - page->setTitle("Start Tutorial 2"); - page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); + if (wizard) delete wizard; + wizard = new TutorialWizard(6); + const auto infotext = + QString("

In tutorial 6 you will learn about setting up a simulation for a molecular " + "system with bonds. The target is to simulate a carbon nanotube with a " + "conventional molecular force field under growing strain and observe the response " + "to it. Since bonds are represented by a harmonic potential, they cannot break. " + "This is then compared to simulating the same system with a reactive force field " + "(AIREBO) where bonds may be broken and formed.


\n

Click on the \"Next\" button to select a folder.

"); + wizard->setFont(font()); + wizard->addPage(tutorial_intro(6)); + wizard->addPage(tutorial_info(6, infotext)); + wizard->addPage(tutorial_directory(6)); + wizard->addPage(tutorial_finish(6)); + wizard->setWindowTitle("Tutorial 6 Setup Wizard"); + wizard->setWizardStyle(QWizard::ModernStyle); + wizard->show(); +} - auto *label = new QLabel("

You are now ready to start tutorial 2.

\n" - "
\n" - "

Click on the \"Finish\" button to " - "complete the setup.

"); - label->setWordWrap(true); +void LammpsGui::start_tutorial7() +{ + if (wizard) delete wizard; + wizard = new TutorialWizard(7); + const auto infotext = + QString("

In tutorial 7 you will learn about setting up a simulation for a molecular " + "system with bonds. The target is to simulate a carbon nanotube with a " + "conventional molecular force field under growing strain and observe the response " + "to it. Since bonds are represented by a harmonic potential, they cannot break. " + "This is then compared to simulating the same system with a reactive force field " + "(AIREBO) where bonds may be broken and formed.


\n

Click on the \"Next\" button to select a folder.

"); + wizard->setFont(font()); + wizard->addPage(tutorial_intro(7)); + wizard->addPage(tutorial_info(7, infotext)); + wizard->addPage(tutorial_directory(7)); + wizard->addPage(tutorial_finish(7)); + wizard->setWindowTitle("Tutorial 7 Setup Wizard"); + wizard->setWizardStyle(QWizard::ModernStyle); + wizard->show(); +} - auto *layout = new QVBoxLayout; - layout->addWidget(label); - layout->setStretch(0, 100); - - page->setLayout(layout); - return page; +void LammpsGui::start_tutorial8() +{ + if (wizard) delete wizard; + wizard = new TutorialWizard(8); + const auto infotext = + QString("

In tutorial 8 you will learn about setting up a simulation for a molecular " + "system with bonds. The target is to simulate a carbon nanotube with a " + "conventional molecular force field under growing strain and observe the response " + "to it. Since bonds are represented by a harmonic potential, they cannot break. " + "This is then compared to simulating the same system with a reactive force field " + "(AIREBO) where bonds may be broken and formed.


\n

Click on the \"Next\" button to select a folder.

"); + wizard->setFont(font()); + wizard->addPage(tutorial_intro(8)); + wizard->addPage(tutorial_info(8, infotext)); + wizard->addPage(tutorial_directory(8)); + wizard->addPage(tutorial_finish(8)); + wizard->setWindowTitle("Tutorial 8 Setup Wizard"); + wizard->setWizardStyle(QWizard::ModernStyle); + wizard->show(); } void LammpsGui::howto() @@ -1983,12 +2013,12 @@ void LammpsGui::start_lammps() lammps.open(narg, args); lammpsstatus->show(); - // must have a version newer than the 2 August 2023 release of LAMMPS + // must have a version newer than the 29 August 2024 release of LAMMPS // TODO: must update this check before next feature release - if (lammps.version() <= 20230802) { + if (lammps.version() < 20240829) { QMessageBox::critical(this, "Incompatible LAMMPS Version", "LAMMPS-GUI version " LAMMPS_GUI_VERSION " requires\n" - "a LAMMPS version more recent than 2 August 2023"); + "a LAMMPS version of at least 29 August 2024"); exit(1); } @@ -2017,7 +2047,8 @@ bool LammpsGui::eventFilter(QObject *watched, QEvent *event) } // LAMMPS geturl command with current location of the input and solution files on the web -static const QString geturl = "geturl https://raw.githubusercontent.com/lammpstutorials/" +static const QString geturl = + "geturl https://raw.githubusercontent.com/lammpstutorials/" "lammpstutorials-article/refs/heads/main/files/tutorial%1/%2 output %2 verify no"; void LammpsGui::setup_tutorial(int tutno, const QString &dir, bool purgedir, bool getsolution) @@ -2071,7 +2102,8 @@ void LammpsGui::setup_tutorial(int tutno, const QString &dir, bool purgedir, boo if (!first.isEmpty()) open_file(first); } -Tutorial1Wizard::Tutorial1Wizard(QWidget *parent) : QWizard(parent) +TutorialWizard::TutorialWizard(int ntutorial, QWidget *parent) : + QWizard(parent), _ntutorial(ntutorial) { setWindowIcon(QIcon(":/icons/tutorial-logo.png")); } @@ -2079,12 +2111,12 @@ Tutorial1Wizard::Tutorial1Wizard(QWidget *parent) : QWizard(parent) // actions to perform when the wizard for tutorial 1 is complete // and the user has clicked on "Finish" -void Tutorial1Wizard::accept() +void TutorialWizard::accept() { // get pointers to the widgets with the information we need - auto *dirname = findChild("t1_directory"); - auto *dirpurge = findChild("t1_dirpurge"); - auto *getsol = findChild("t1_getsolution"); + auto *dirname = findChild("t_directory"); + auto *dirpurge = findChild("t_dirpurge"); + auto *getsol = findChild("t_getsolution"); // create and populate directory. if (dirname) { @@ -2092,8 +2124,8 @@ void Tutorial1Wizard::accept() auto curdir = dirname->text().trimmed(); if (!directory.mkpath(curdir)) { QMessageBox::warning(this, "Warning", - "Cannot create tutorial 1 working directory " + curdir + - ".\n\nGoing back to directory selection."); + "Cannot create tutorial working directory '" + curdir + + "'.\n\nGoing back to directory selection."); back(); return; } @@ -2105,46 +2137,7 @@ void Tutorial1Wizard::accept() LammpsGui *main = nullptr; for (QWidget *widget : QApplication::topLevelWidgets()) if (widget->objectName() == "LammpsGui") main = dynamic_cast(widget); - if (main) main->setup_tutorial(1, curdir, purgedir, getsolution); - } - QDialog::accept(); -} - -Tutorial2Wizard::Tutorial2Wizard(QWidget *parent) : QWizard(parent) -{ - setWindowIcon(QIcon(":/icons/tutorial-logo.png")); -} - -// actions to perform when the wizard for tutorial 2 is complete -// and the user has clicked on "Finish" - -void Tutorial2Wizard::accept() -{ - // get pointers to the widgets with the information we need - auto *dirname = findChild("t2_directory"); - auto *dirpurge = findChild("t2_dirpurge"); - auto *getsol = findChild("t2_getsolution"); - - // create and populate directory. - if (dirname) { - QDir directory; - auto curdir = dirname->text().trimmed(); - if (!directory.mkpath(curdir)) { - QMessageBox::warning(this, "Warning", - "Cannot create tutorial 2 working directory " + curdir + - ".\n\nGoing back to directory selection."); - back(); - return; - } - - bool purgedir = dirpurge && (dirpurge->checkState() == Qt::Checked); - bool getsolution = getsol && (getsol->checkState() == Qt::Checked); - - // get hold of LAMMPS-GUI main widget - LammpsGui *main = nullptr; - for (QWidget *widget : QApplication::topLevelWidgets()) - if (widget->objectName() == "LammpsGui") main = dynamic_cast(widget); - if (main) main->setup_tutorial(2, curdir, purgedir, getsolution); + if (main) main->setup_tutorial(_ntutorial, curdir, purgedir, getsolution); } QDialog::accept(); } diff --git a/tools/lammps-gui/lammpsgui.h b/tools/lammps-gui/lammpsgui.h index a269e1a384..9b85fc140a 100644 --- a/tools/lammps-gui/lammpsgui.h +++ b/tools/lammps-gui/lammpsgui.h @@ -64,8 +64,7 @@ class LammpsGui : public QMainWindow { friend class CodeEditor; friend class GeneralTab; - friend class Tutorial1Wizard; - friend class Tutorial2Wizard; + friend class TutorialWizard; public: LammpsGui(QWidget *parent = nullptr, const QString &filename = QString()); @@ -84,15 +83,11 @@ protected: void setDocver(); void autoSave(); void setFont(const QFont &newfont); - QWizardPage *tutorial1_intro(); - QWizardPage *tutorial1_info(); - QWizardPage *tutorial1_directory(); - QWizardPage *tutorial1_finish(); - QWizardPage *tutorial2_intro(); - QWizardPage *tutorial2_info(); - QWizardPage *tutorial2_directory(); - QWizardPage *tutorial2_finish(); - void setup_tutorial(int tutno, const QString &dir, bool purgedir, bool getsolution); + QWizardPage *tutorial_intro(const int ntutorial); + QWizardPage *tutorial_info(const int ntutorial, const QString &infotext); + QWizardPage *tutorial_directory(const int ntutorial); + QWizardPage *tutorial_finish(const int ntutorial); + void setup_tutorial(int ntutorial, const QString &dir, bool purgedir, bool getsolution); void purge_inspect_list(); bool eventFilter(QObject *watched, QEvent *event) override; @@ -132,6 +127,12 @@ private slots: void tutorial_web(); void start_tutorial1(); void start_tutorial2(); + void start_tutorial3(); + void start_tutorial4(); + void start_tutorial5(); + void start_tutorial6(); + void start_tutorial7(); + void start_tutorial8(); void howto(); void logupdate(); void modified(); @@ -178,20 +179,14 @@ private: std::vector lammps_args; }; -class Tutorial1Wizard : public QWizard { +class TutorialWizard : public QWizard { Q_OBJECT public: - Tutorial1Wizard(QWidget *parent = nullptr); - void accept() override; -}; - -class Tutorial2Wizard : public QWizard { - Q_OBJECT - -public: - Tutorial2Wizard(QWidget *parent = nullptr); + TutorialWizard(int ntutorial, QWidget *parent = nullptr); void accept() override; +private: + int _ntutorial; }; #endif // LAMMPSGUI_H diff --git a/tools/lammps-gui/lammpsgui.ui b/tools/lammps-gui/lammpsgui.ui index 045e0f84a8..c6dbd6a507 100644 --- a/tools/lammps-gui/lammpsgui.ui +++ b/tools/lammps-gui/lammpsgui.ui @@ -87,6 +87,12 @@ + + + + + + @@ -510,6 +516,54 @@ Start LAMMPS Tutorial &2 + + + + + + Start LAMMPS Tutorial &3 + + + + + + + + Start LAMMPS Tutorial &4 + + + + + + + + Start LAMMPS Tutorial &5 + + + + + + + + Start LAMMPS Tutorial &6 + + + + + + + + Start LAMMPS Tutorial &7 + + + + + + + + Start LAMMPS Tutorial &8 + +