Merge branch 'develop' into next_release

This commit is contained in:
Axel Kohlmeyer
2024-08-28 22:12:31 -04:00
76 changed files with 2172 additions and 1295 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(lammps-gui VERSION 1.6.9 LANGUAGES CXX)
project(lammps-gui VERSION 1.6.10 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
@ -130,6 +130,8 @@ set(PROJECT_SOURCES
chartviewer.h
codeeditor.cpp
codeeditor.h
findandreplace.cpp
findandreplace.h
helpers.cpp
highlighter.cpp
highlighter.h

View File

@ -2,12 +2,21 @@ LAMMPS-GUI TODO list:
# Short term goals (v1.x)
- implement a timed "Auto-Save" feature that saves after some idle time. set timeout in Editor preferences.
- add a "Filter data" checkbox to the "Charts" window to select whether data should be dropped.
- add a "Charts tab" to the preferences with the following (default) settings:
- default filter data yes/no
- default smooth parameters
- default plot colors
- enable "raw" or "smooth" or "both"
- add QLineEdit field to enter plot title
- add a "Colors" menu to the image viewer to adjust color settings for the
current image (unlike the defaults in the perferences) including assigning
colors to individual atom types.
- Support color by property (e.g. scan computes or fixes with per-atom data), define colormaps etc.
- Add a "Diameters" dialog where diamaters can by specified by atom type
- figure out how widgets can be resized to fraction of available screen size.
- figure out stacking order of frames and whether it can be more flexible
- implement a timed "Auto-Save" feature that saves after some idle time. set timeout in Editor preferences.
- add a "Colors" menu to the image viewer to adjust color settings for the
current image (unlike the defaults in the perferences). Support color by
property (e.g. scan computes or fixes with per-atom data), define colormaps etc.
- implement indenting regions for (nested) loops?
- implement data file manager GUI with the following features:

View File

@ -424,7 +424,7 @@ void ChartViewer::add_data(int step, double data)
if (last_step < step) {
last_step = step;
// do not add data that deviates by more than 5 sigma from the average
// do not add data that deviates by more than 4 sigma from the average
// over the last 5 to 20 data items. this is a hack to work around
// getting corrupted data from lammps_get_last_thermo()
const auto &points = series->points();

View File

@ -218,7 +218,10 @@ CodeEditor::CodeEditor(QWidget *parent) :
help_index.close();
}
setBackgroundRole(QPalette::Light);
lineNumberArea = new LineNumberArea(this);
lineNumberArea->setBackgroundRole(QPalette::Dark);
lineNumberArea->setAutoFillBackground(true);
connect(this, &CodeEditor::blockCountChanged, this, &CodeEditor::updateLineNumberAreaWidth);
connect(this, &CodeEditor::updateRequest, this, &CodeEditor::updateLineNumberArea);
updateLineNumberAreaWidth(0);
@ -669,7 +672,7 @@ void CodeEditor::lineNumberAreaPaintEvent(QPaintEvent *event)
if (block.isVisible() && bottom >= event->rect().top()) {
QString number = QString::number(blockNumber + 1) + " ";
if ((highlight == NO_HIGHLIGHT) || (blockNumber != std::abs(highlight))) {
painter.setPen(Qt::black);
painter.setPen(palette().color(QPalette::WindowText));
} else {
number = QString(">") + QString::number(blockNumber + 1) + "<";
if (highlight < 0)

View File

@ -0,0 +1,148 @@
/* ----------------------------------------------------------------------
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.
------------------------------------------------------------------------- */
#include "findandreplace.h"
#include "codeeditor.h"
#include "lammpsgui.h"
#include <QApplication>
#include <QCheckBox>
#include <QDialogButtonBox>
#include <QGridLayout>
#include <QHBoxLayout>
#include <QIcon>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QShortcut>
#include <QSizePolicy>
#include <QTextCursor>
/* ---------------------------------------------------------------------- */
FindAndReplace::FindAndReplace(CodeEditor *_editor, QWidget *parent) :
QDialog(parent), editor(_editor), search(nullptr), replace(nullptr), withcase(nullptr),
wrap(nullptr), whole(nullptr)
{
auto *layout = new QGridLayout;
search = new QLineEdit;
replace = new QLineEdit;
withcase = new QCheckBox("Match case");
wrap = new QCheckBox("Wrap around");
whole = new QCheckBox("Whole word");
auto *next = new QPushButton("&Next");
auto *replone = new QPushButton("&Replace");
auto *replall = new QPushButton("Replace &All");
auto *done = new QPushButton("&Done");
layout->addWidget(new QLabel("Find:"), 0, 0, Qt::AlignRight);
layout->addWidget(search, 0, 1, 1, 2, Qt::AlignLeft);
layout->addWidget(new QLabel("Replace with:"), 1, 0, Qt::AlignRight);
layout->addWidget(replace, 1, 1, 1, 2, Qt::AlignLeft);
layout->addWidget(withcase, 2, 0, Qt::AlignLeft);
layout->addWidget(wrap, 2, 1, Qt::AlignLeft);
layout->addWidget(whole, 2, 2, Qt::AlignLeft);
wrap->setChecked(true);
auto *buttons = new QHBoxLayout;
buttons->addWidget(next);
buttons->addWidget(replone);
buttons->addWidget(replall);
buttons->addWidget(done);
layout->addLayout(buttons, 3, 0, 1, 3, Qt::AlignHCenter);
connect(next, &QPushButton::released, this, &FindAndReplace::find_next);
connect(replone, &QPushButton::released, this, &FindAndReplace::replace_next);
connect(replall, &QPushButton::released, this, &FindAndReplace::replace_all);
connect(done, &QPushButton::released, this, &QDialog::accept);
auto action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
connect(action, &QShortcut::activated, this, &FindAndReplace::quit);
setLayout(layout);
setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png"));
setWindowTitle("LAMMPS-GUI - Find and Replace");
}
/* ---------------------------------------------------------------------- */
void FindAndReplace::find_next()
{
auto text = search->text();
int find_flags = 0;
if (withcase->isChecked()) find_flags |= QTextDocument::FindCaseSensitively;
if (whole->isChecked()) find_flags |= QTextDocument::FindWholeWords;
if (!text.isEmpty()) {
if (!editor->find(text, (QTextDocument::FindFlag)find_flags) && wrap->isChecked()) {
// nothing found from the current position to the end, reposition cursor and beginning
editor->moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor);
editor->find(text, (QTextDocument::FindFlag)find_flags);
}
}
}
/* ---------------------------------------------------------------------- */
void FindAndReplace::replace_next()
{
auto text = search->text();
if (text.isEmpty()) return;
auto cursor = editor->textCursor();
auto flag = withcase->isChecked() ? Qt::CaseSensitive : Qt::CaseInsensitive;
// if selected text at cursor location matches search text, replace
if (QString::compare(cursor.selectedText(), search->text(), flag) == 0)
cursor.insertText(replace->text());
find_next();
}
/* ---------------------------------------------------------------------- */
void FindAndReplace::replace_all()
{
auto text = search->text();
if (text.isEmpty()) return;
// drop selection if we have one
auto cursor = editor->textCursor();
if (cursor.hasSelection()) cursor.movePosition(QTextCursor::Left);
find_next();
cursor = editor->textCursor();
// keep replacing until find_next() does not find anything anymore
while (cursor.hasSelection()) {
cursor.insertText(replace->text());
find_next();
cursor = editor->textCursor();
}
}
/* ---------------------------------------------------------------------- */
void FindAndReplace::quit()
{
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
if (main) main->quit();
}
// Local Variables:
// c-basic-offset: 4
// End:

View File

@ -0,0 +1,46 @@
/* -*- 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 FIND_AND_REPLACE_H
#define FIND_AND_REPLACE_H
#include "codeeditor.h"
#include <QDialog>
class QLineEdit;
class QCheckBox;
class FindAndReplace : public QDialog {
Q_OBJECT
public:
explicit FindAndReplace(CodeEditor *_editor, QWidget *parent = nullptr);
~FindAndReplace() = default;
private slots:
void find_next();
void replace_next();
void replace_all();
void quit();
private:
CodeEditor *editor;
QLineEdit *search, *replace;
QCheckBox *withcase, *wrap, *whole;
};
#endif
// Local Variables:
// c-basic-offset: 4
// End:

View File

@ -13,9 +13,12 @@
#include "helpers.h"
#include <QBrush>
#include <QColor>
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QPalette>
#include <QProcess>
#include <QStringList>
@ -84,6 +87,16 @@ void purge_directory(const QString &dir)
}
}
// compare black level of foreground and background color
bool is_light_theme()
{
QPalette p;
int fg = p.brush(QPalette::Active, QPalette::WindowText).color().black();
int bg = p.brush(QPalette::Active, QPalette::Window).color().black();
return (fg > bg);
}
// Local Variables:
// c-basic-offset: 4
// End:

View File

@ -28,6 +28,9 @@ extern bool has_exe(const QString &exe);
// recursively purge a directory
extern void purge_directory(const QString &dir);
// flag if light or dark theme
extern bool is_light_theme();
#endif
// Local Variables:
// c-basic-offset: 4

View File

@ -12,6 +12,28 @@
------------------------------------------------------------------------- */
#include "highlighter.h"
#include "helpers.h"
#include <QColor>
// workaround for Qt-5.12
#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
namespace QColorConstants {
const QColor Red = QColor::fromRgb(0xff, 0x00, 0x00);
const QColor Green = QColor::fromRgb(0x00, 0xff, 0x00);
const QColor Blue = QColor::fromRgb(0x00, 0x00, 0xff);
const QColor Cyan = QColor::fromRgb(0x00, 0xff, 0xff);
const QColor Magenta = QColor::fromRgb(0xff, 0x00, 0xff);
const QColor Yellow = QColor::fromRgb(0xff, 0xff, 0x00);
namespace Svg {
const QColor dodgerblue = QColor::fromRgb(0x1e, 0x90, 0xff);
const QColor indianred = QColor::fromRgb(0xcd, 0x5c, 0x5c);
const QColor lightcoral = QColor::fromRgb(0xf0, 0x80, 0x80);
const QColor lightgray = QColor::fromRgb(0xd3, 0xd3, 0xd3);
const QColor lightgreen = QColor::fromRgb(0x90, 0xee, 0x90);
const QColor lightskyblue = QColor::fromRgb(0x87, 0xce, 0xfa);
} // namespace Svg
} // namespace QColorConstants
#endif
Highlighter::Highlighter(QTextDocument *parent) :
QSyntaxHighlighter(parent),
@ -54,27 +76,54 @@ Highlighter::Highlighter(QTextDocument *parent) :
isTriple(QStringLiteral("[^\"]*\"\"\"[^\"]*")),
isString(QStringLiteral("(\".+?\"|'.+?'|\"\"\".*\"\"\")")), in_triple(false)
{
formatNumber.setForeground(Qt::blue);
formatString.setForeground(Qt::darkGreen);
formatString.setFontWeight(QFont::Normal);
formatComment.setForeground(Qt::red);
formatSpecial.setForeground(Qt::darkMagenta);
formatSpecial.setFontWeight(QFont::Bold);
formatParticle.setForeground(Qt::darkRed);
formatParticle.setFontWeight(QFont::Bold);
formatRun.setForeground(Qt::darkBlue);
formatRun.setFontWeight(QFont::Bold);
formatVariable.setForeground(Qt::darkGray);
formatVariable.setFontWeight(QFont::Bold);
if (is_light_theme()) {
// syntax colors for light themes
formatNumber.setForeground(Qt::blue);
formatString.setForeground(Qt::darkGreen);
formatString.setFontWeight(QFont::Normal);
formatComment.setForeground(Qt::red);
formatSpecial.setForeground(Qt::darkMagenta);
formatSpecial.setFontWeight(QFont::Bold);
formatParticle.setForeground(Qt::darkRed);
formatParticle.setFontWeight(QFont::Bold);
formatRun.setForeground(Qt::darkBlue);
formatRun.setFontWeight(QFont::Bold);
formatVariable.setForeground(Qt::darkGray);
formatVariable.setFontWeight(QFont::Bold);
formatOutput.setForeground(Qt::darkYellow);
formatOutput.setFontWeight(QFont::Bold);
formatRead.setForeground(Qt::magenta);
formatRead.setFontWeight(QFont::Bold);
formatLattice.setForeground(Qt::darkGreen);
formatLattice.setFontWeight(QFont::Bold);
formatSetup.setForeground(Qt::darkCyan);
formatSetup.setFontWeight(QFont::Bold);
formatOutput.setForeground(Qt::darkYellow);
formatOutput.setFontWeight(QFont::Bold);
formatRead.setForeground(Qt::magenta);
formatRead.setFontWeight(QFont::Bold);
formatLattice.setForeground(Qt::darkGreen);
formatLattice.setFontWeight(QFont::Bold);
formatSetup.setForeground(Qt::darkCyan);
formatSetup.setFontWeight(QFont::Bold);
} else {
// syntax colors for dark themes
formatNumber.setForeground(QColorConstants::Svg::dodgerblue);
formatString.setForeground(QColorConstants::Green);
formatString.setFontWeight(QFont::Normal);
formatComment.setForeground(QColorConstants::Red);
formatComment.setFontWeight(QFont::Bold);
formatSpecial.setForeground(QColorConstants::Magenta);
formatSpecial.setFontWeight(QFont::Bold);
formatParticle.setForeground(QColorConstants::Svg::indianred);
formatParticle.setFontWeight(QFont::Bold);
formatRun.setForeground(QColorConstants::Svg::lightskyblue);
formatRun.setFontWeight(QFont::Bold);
formatVariable.setForeground(QColorConstants::Svg::lightgray);
formatVariable.setFontWeight(QFont::Bold);
formatOutput.setForeground(QColorConstants::Yellow);
formatOutput.setFontWeight(QFont::Bold);
formatRead.setForeground(QColorConstants::Svg::lightcoral);
formatRead.setFontWeight(QFont::Bold);
formatLattice.setForeground(QColorConstants::Svg::lightgreen);
formatLattice.setFontWeight(QFont::Bold);
formatSetup.setForeground(QColorConstants::Cyan);
formatSetup.setFontWeight(QFont::Bold);
}
}
void Highlighter::highlightBlock(const QString &text)

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@ -20,6 +20,7 @@
#include <QApplication>
#include <QClipboard>
#include <QDir>
#include <QDoubleValidator>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
@ -31,6 +32,7 @@
#include <QImageReader>
#include <QKeySequence>
#include <QLabel>
#include <QLineEdit>
#include <QMenu>
#include <QMenuBar>
#include <QPalette>
@ -135,9 +137,10 @@ static const QString blank(" ");
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) :
QDialog(parent), menuBar(new QMenuBar), imageLabel(new QLabel), scrollArea(new QScrollArea),
saveAsAct(nullptr), copyAct(nullptr), cmdAct(nullptr), zoomInAct(nullptr), zoomOutAct(nullptr),
normalSizeAct(nullptr), lammps(_lammps), group("all"), filename(fileName), useelements(false),
usediameter(false), usesigma(false)
buttonBox(nullptr), scaleFactor(1.0), atomSize(1.0), saveAsAct(nullptr), copyAct(nullptr),
cmdAct(nullptr), zoomInAct(nullptr), zoomOutAct(nullptr), normalSizeAct(nullptr),
lammps(_lammps), group("all"), filename(fileName), useelements(false), usediameter(false),
usesigma(false)
{
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
@ -163,6 +166,13 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
renderstatus->setEnabled(false);
renderstatus->setToolTip("Render status");
renderstatus->setObjectName("renderstatus");
auto *asize = new QLineEdit(QString::number(atomSize));
auto *valid = new QDoubleValidator(1.0e-10, 1.0e10, 10, asize);
asize->setValidator(valid);
asize->setObjectName("atomSize");
asize->setToolTip("Set Atom size");
asize->setEnabled(false);
asize->hide();
settings.beginGroup("snapshot");
auto *xval = new QSpinBox;
xval->setRange(100, 10000);
@ -179,6 +189,7 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
yval->setToolTip("Set rendered image height");
yval->setMinimumSize(bsize);
settings.endGroup();
connect(asize, &QLineEdit::editingFinished, this, &ImageViewer::set_atom_size);
connect(xval, &QAbstractSpinBox::editingFinished, this, &ImageViewer::edit_size);
connect(yval, &QAbstractSpinBox::editingFinished, this, &ImageViewer::edit_size);
@ -249,6 +260,11 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
menuLayout->addWidget(menuBar);
menuLayout->addWidget(renderstatus);
menuLayout->addWidget(new QLabel(" Atom Size: "));
menuLayout->addWidget(asize);
// hide item initially
menuLayout->itemAt(2)->widget()->setObjectName("AtomLabel");
menuLayout->itemAt(2)->widget()->hide();
menuLayout->addWidget(new QLabel(" Width: "));
menuLayout->addWidget(xval);
menuLayout->addWidget(new QLabel(" Height: "));
@ -307,7 +323,7 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
doanti->setChecked(antialias);
scaleFactor = 1.0;
resize(image.width() + 20, image.height() + 75);
resize(image.width() + 25, image.height() + 80);
scrollArea->setVisible(true);
updateActions();
@ -356,6 +372,13 @@ void ImageViewer::reset_view()
createImage();
}
void ImageViewer::set_atom_size()
{
auto *field = qobject_cast<QLineEdit *>(sender());
atomSize = field->text().toDouble();
createImage();
}
void ImageViewer::edit_size()
{
auto *field = qobject_cast<QSpinBox *>(sender());
@ -560,10 +583,43 @@ void ImageViewer::createImage()
if (useelements || usediameter || usesigma) {
auto *button = findChild<QPushButton *>("vdw");
if (button) button->setEnabled(true);
auto *edit = findChild<QLineEdit *>("atomSize");
if (edit) {
edit->setEnabled(false);
edit->hide();
}
auto *label = findChild<QLabel *>("AtomLabel");
if (label) {
label->setEnabled(false);
label->hide();
}
} else {
adiams.clear();
auto *button = findChild<QPushButton *>("vdw");
if (button) button->setEnabled(false);
auto *label = findChild<QLabel *>("AtomLabel");
if (label) {
label->setEnabled(true);
label->show();
}
auto *edit = findChild<QLineEdit *>("atomSize");
if (edit) {
if (!edit->isEnabled()) {
edit->setEnabled(true);
edit->show();
// initialize with lattice spacing
auto *xlattice = (const double *)lammps->extract_global("xlattice");
if (xlattice) atomSize = *xlattice;
edit->setText(QString::number(atomSize));
}
atomSize = edit->text().toDouble();
}
if (atomSize != 1.0) {
for (int i = 1; i <= ntypes; ++i)
adiams += QString("adiam %1 %2 ").arg(i).arg(atomSize);
}
}
// color
@ -607,6 +663,7 @@ void ImageViewer::createImage()
dumpcmd += " backcolor " + settings.value("background", "black").toString();
if (useelements) dumpcmd += blank + elements + blank + adiams + blank;
if (usesigma) dumpcmd += blank + adiams + blank;
if (!useelements && !usesigma && (atomSize != 1.0)) dumpcmd += blank + adiams + blank;
settings.endGroup();
last_dump_cmd = dumpcmd;
@ -617,10 +674,10 @@ void ImageViewer::createImage()
const QImage newImage = reader.read();
dumpfile.remove();
// read of new image failed. Don't try to scale and load it.
// read of new image failed. nothing left to do.
if (newImage.isNull()) return;
// scale back to achieve antialiasing
// show show image
image = newImage;
imageLabel->setPixmap(QPixmap::fromImage(image));
imageLabel->adjustSize();

View File

@ -34,13 +34,15 @@ class ImageViewer : public QDialog {
Q_OBJECT
public:
explicit ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent = nullptr);
explicit ImageViewer(const QString &fileName, LammpsWrapper *_lammps,
QWidget *parent = nullptr);
private slots:
void saveAs();
void copy();
void quit();
void set_atom_size();
void edit_size();
void reset_view();
void toggle_ssao();
@ -75,7 +77,8 @@ private:
QLabel *imageLabel;
QScrollArea *scrollArea;
QDialogButtonBox *buttonBox;
double scaleFactor = 1.0;
double scaleFactor;
double atomSize;
QAction *saveAsAct;
QAction *copyAct;

View File

@ -54,8 +54,17 @@
</provides>
<releases>
<release version="1.6.10" timestamp="1724585189">
<description>
</description>
</release>
<release version="1.6.9" timestamp="1724308872">
<description>
Added search and replace functionality
Converged command line argument parsing using Qt facilities
Added dark mode adjustments to syntax highlighting
Add field to enter Atom size, if not determined otherwise
</description>
</release>
<release version="1.6.8" timestamp="1723581926">

View File

@ -15,6 +15,7 @@
#include "chartviewer.h"
#include "fileviewer.h"
#include "findandreplace.h"
#include "helpers.h"
#include "highlighter.h"
#include "imageviewer.h"
@ -68,18 +69,13 @@
static const QString blank(" ");
static constexpr int BUFLEN = 256;
LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
LammpsGui::LammpsGui(QWidget *parent, const QString &filename) :
QMainWindow(parent), ui(new Ui::LammpsGui), highlighter(nullptr), capturer(nullptr),
status(nullptr), logwindow(nullptr), imagewindow(nullptr), chartwindow(nullptr),
slideshow(nullptr), logupdater(nullptr), dirstatus(nullptr), progress(nullptr),
prefdialog(nullptr), lammpsstatus(nullptr), varwindow(nullptr), wizard(nullptr),
runner(nullptr), is_running(false), run_counter(0)
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// register QList<QString> only needed for Qt5
qRegisterMetaTypeStreamOperators<QList<QString>>("QList<QString>");
#endif
docver = "";
ui->setupUi(this);
this->setCentralWidget(ui->textEdit);
@ -90,27 +86,34 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
// use $HOME if we get dropped to "/" like on macOS
if (current_dir == "/") current_dir = QDir::homePath();
inspectList.clear();
setAutoFillBackground(true);
// restore and initialize settings
QSettings settings;
#if defined(LAMMPS_GUI_USE_PLUGIN)
plugin_path.clear();
std::string deffile = settings.value("plugin_path", "liblammps.so").toString().toStdString();
for (const char *libfile : {deffile.c_str(), "./liblammps.so", "liblammps.dylib",
"./liblammps.dylib", "liblammps.dll"}) {
if (lammps.load_lib(libfile)) {
auto canonical = QFileInfo(libfile).canonicalFilePath();
plugin_path = canonical.toStdString();
settings.setValue("plugin_path", canonical);
break;
plugin_path =
QFileInfo(settings.value("plugin_path", "liblammps.so").toString()).canonicalFilePath();
if (!lammps.load_lib(plugin_path.toStdString().c_str())) {
// fall back to defaults
for (const char *libfile :
{"./liblammps.so", "liblammps.dylib", "./liblammps.dylib", "liblammps.dll"}) {
if (lammps.load_lib(libfile)) {
plugin_path = QFileInfo(libfile).canonicalFilePath();
settings.setValue("plugin_path", plugin_path);
break;
} else {
plugin_path.clear();
}
}
}
if (plugin_path.empty()) {
if (plugin_path.isEmpty()) {
// none of the plugin paths could load, remove key
settings.remove("plugin_path");
QMessageBox::critical(this, "Error", "Cannot open LAMMPS shared library file");
QMessageBox::critical(this, "Error",
"Cannot open LAMMPS shared library file.\n"
"Use -p command line flag to specify a path to the library.");
exit(1);
}
#endif
@ -205,6 +208,7 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
connect(ui->actionPaste, &QAction::triggered, this, &LammpsGui::paste);
connect(ui->actionUndo, &QAction::triggered, this, &LammpsGui::undo);
connect(ui->actionRedo, &QAction::triggered, this, &LammpsGui::redo);
connect(ui->actionSearchAndReplace, &QAction::triggered, this, &LammpsGui::findandreplace);
connect(ui->actionRun_Buffer, &QAction::triggered, this, &LammpsGui::run_buffer);
connect(ui->actionRun_File, &QAction::triggered, this, &LammpsGui::run_file);
connect(ui->actionStop_LAMMPS, &QAction::triggered, this, &LammpsGui::stop_run);
@ -278,7 +282,7 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
dirstatus->show();
ui->statusbar->addWidget(progress);
if (filename) {
if (filename.size() > 0) {
open_file(filename);
} else {
setWindowTitle("LAMMPS-GUI - Editor - *unknown*");
@ -502,7 +506,7 @@ void LammpsGui::start_exe()
void LammpsGui::update_recents(const QString &filename)
{
QSettings settings;
recent = settings.value("recent").value<QList<QString>>();
if (settings.contains("recent")) recent = settings.value("recent").value<QList<QString>>();
for (int i = 0; i < recent.size(); ++i) {
QFileInfo fi(recent[i]);
@ -514,7 +518,10 @@ void LammpsGui::update_recents(const QString &filename)
if (!filename.isEmpty() && !recent.contains(filename)) recent.prepend(filename);
if (recent.size() > 5) recent.removeLast();
settings.setValue("recent", QVariant::fromValue(recent));
if (recent.size() > 0)
settings.setValue("recent", QVariant::fromValue(recent));
else
settings.remove("recent");
ui->action_1->setVisible(false);
if ((recent.size() > 0) && !recent[0].isEmpty()) {
@ -1428,12 +1435,16 @@ void LammpsGui::setFont(const QFont &newfont)
void LammpsGui::about()
{
std::string version = "This is LAMMPS-GUI version " LAMMPS_GUI_VERSION;
version += " using Qt version " QT_VERSION_STR "\n";
version += " using Qt version " QT_VERSION_STR;
if (is_light_theme())
version += " using light theme\n";
else
version += " using dark theme\n";
if (lammps.has_plugin()) {
version += "LAMMPS library loaded as plugin";
if (!plugin_path.empty()) {
if (!plugin_path.isEmpty()) {
version += " from file ";
version += plugin_path;
version += plugin_path.toStdString();
}
} else {
version += "LAMMPS library linked to executable";
@ -1862,6 +1873,14 @@ void LammpsGui::edit_variables()
}
}
void LammpsGui::findandreplace()
{
FindAndReplace find(ui->textEdit, this);
find.setFont(font());
find.setObjectName("find");
find.exec();
}
void LammpsGui::preferences()
{
QSettings settings;

View File

@ -68,7 +68,7 @@ class LammpsGui : public QMainWindow {
friend class Tutorial2Wizard;
public:
LammpsGui(QWidget *parent = nullptr, const char *filename = nullptr);
LammpsGui(QWidget *parent = nullptr, const QString &filename = QString());
~LammpsGui() override;
protected:
@ -115,6 +115,7 @@ private slots:
void paste();
void undo();
void redo();
void findandreplace();
void run_buffer() { do_run(true); }
void run_file() { do_run(false); }
@ -171,7 +172,7 @@ private:
LammpsWrapper lammps;
LammpsRunner *runner;
QString docver;
std::string plugin_path;
QString plugin_path;
bool is_running;
int run_counter;
std::vector<char *> lammps_args;

View File

@ -58,6 +58,7 @@
<file>icons/preferences-desktop.png</file>
<file>icons/process-stop.png</file>
<file>icons/run-file.png</file>
<file>icons/search.png</file>
<file>icons/system-box.png</file>
<file>icons/system-help.png</file>
<file>icons/system-run.png</file>

View File

@ -62,6 +62,8 @@
<addaction name="actionCut"/>
<addaction name="actionPaste"/>
<addaction name="separator"/>
<addaction name="actionSearchAndReplace"/>
<addaction name="separator"/>
<addaction name="actionPreferences"/>
<addaction name="actionDefaults"/>
</widget>
@ -312,12 +314,23 @@
<string>Ctrl+Shift+H</string>
</property>
</action>
<action name="actionSearchAndReplace">
<property name="icon">
<iconset theme=":/icons/search.png"/>
</property>
<property name="text">
<string>&amp;Find and Replace...</string>
</property>
<property name="shortcut">
<string>Ctrl+F</string>
</property>
</action>
<action name="actionPreferences">
<property name="icon">
<iconset theme=":/icons/preferences-desktop.png"/>
</property>
<property name="text">
<string>Pre&amp;ferences...</string>
<string>P&amp;references...</string>
</property>
<property name="shortcut">
<string>Ctrl+P</string>

View File

@ -115,7 +115,7 @@ double LammpsWrapper::extract_variable(const char *keyword)
}
double val = *((double *)ptr);
#if defined(LAMMPS_GUI_USE_PLUGIN)
ptr = ((liblammpsplugin_t *)plugin_handle)->free(ptr);
((liblammpsplugin_t *)plugin_handle)->free(ptr);
#else
lammps_free(ptr);
#endif

View File

@ -17,6 +17,9 @@
#include <QCommandLineOption>
#include <QCommandLineParser>
#include <QLocale>
#include <QSettings>
#include <QString>
#include <QStringList>
#include <cstdio>
#include <cstring>
@ -27,6 +30,11 @@
int main(int argc, char *argv[])
{
Q_INIT_RESOURCE(lammpsgui);
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// register QList<QString> only needed for Qt5
qRegisterMetaTypeStreamOperators<QList<QString>>("QList<QString>");
#endif
QApplication app(argc, argv);
// enforce using the plain ASCII C locale within the GUI.
QLocale::setDefault(QLocale::c());
@ -40,13 +48,32 @@ int main(int argc, char *argv[])
"\nA graphical editor for LAMMPS input files with syntax highlighting and\n"
"auto-completion that can run LAMMPS directly. It has built-in capabilities\n"
"for monitoring, visualization, plotting, and capturing console output.");
#if defined(LAMMPS_GUI_USE_PLUGIN)
QCommandLineOption plugindir(QStringList() << "p"
<< "pluginpath",
"Path to LAMMPS shared library", "path");
parser.addOption(plugindir);
#endif
parser.addHelpOption();
parser.addVersionOption();
parser.addPositionalArgument("file", "The LAMMPS input file to open (optional).");
parser.process(app); // this removes known arguments
parser.process(app);
const char *infile = nullptr;
if (argc > 1) infile = argv[1];
#if defined(LAMMPS_GUI_USE_PLUGIN)
if (parser.isSet(plugindir)) {
QStringList pluginpath = parser.values(plugindir);
if (pluginpath.length() > 0) {
QSettings settings;
settings.setValue("plugin_path", QString(pluginpath.at(0)));
settings.sync();
}
}
#endif
QString infile;
QStringList args = parser.positionalArguments();
if (args.size() > 0) infile = args[0];
LammpsGui w(nullptr, infile);
w.show();
return app.exec();