diff --git a/tools/lammps-gui/chartviewer.cpp b/tools/lammps-gui/chartviewer.cpp index 676a658f95..23928d8aeb 100644 --- a/tools/lammps-gui/chartviewer.cpp +++ b/tools/lammps-gui/chartviewer.cpp @@ -13,18 +13,95 @@ #include "chartviewer.h" +#include #include #include +#include using namespace QtCharts; -ChartViewer::ChartViewer(QWidget *parent) : - QChartView(parent), last_step(-1), chart(new QChart), series(new QLineSeries), +ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) : + QWidget(parent), menu(new QMenuBar), file(new QMenu("&File")), active_chart(-1), + filename(_filename) +{ + auto *top = new QHBoxLayout; + menu->addMenu(file); + menu->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); + + columns = new QComboBox; + top->addWidget(menu); + top->addWidget(columns); + saveAsAct = file->addAction("&Save Graph As...", this, &ChartWindow::saveAs); + closeAct = file->addAction("&Close", this, &QWidget::close); + auto *layout = new QVBoxLayout; + layout->addLayout(top); + setLayout(layout); + + connect(columns, SIGNAL(currentIndexChanged(int)), this, SLOT(change_chart(int))); + QSettings settings; + resize(settings.value("chartx", 500).toInt(), settings.value("charty", 320).toInt()); +} + +void ChartWindow::add_chart(const QString &title, int index) +{ + auto *chart = new ChartViewer(title, index); + layout()->addWidget(chart); + columns->addItem(title, index); + columns->show(); + // hide all but the first chart added + if (charts.size() > 0) chart->hide(); + charts.append(chart); + active_chart = 0; +} + +void ChartWindow::add_data(int step, double data, int index) +{ + for (auto &c : charts) + if (c->get_index() == index) c->add_data(step, data); +} + +void ChartWindow::saveAs() +{ + if (charts.empty() || (active_chart < 0)) return; + QString defaultname = filename + "." + columns->currentText() + ".png"; + if (filename.isEmpty()) defaultname = columns->currentText() + ".png"; + QString fileName = QFileDialog::getSaveFileName(this, "Save Chart as Image", defaultname, + "Image Files (*.jpg *.png *.bmp *.ppm)"); + if (!fileName.isEmpty()) { + charts[active_chart]->grab().save(fileName); + } +} + +void ChartWindow::change_chart(int index) +{ + int choice = columns->currentData().toInt(); + for (auto &c : charts) { + if (choice == c->get_index()) + c->show(); + else + c->hide(); + } +} + +void ChartWindow::closeEvent(QCloseEvent *event) +{ + QSettings settings; + if (!isMaximized()) { + settings.setValue("chartx", width()); + settings.setValue("charty", height()); + } + QWidget::closeEvent(event); +} + +/* -------------------------------------------------------------------- */ + +ChartViewer::ChartViewer(const QString &title, int _index, QWidget *parent) : + QChartView(parent), last_step(-1), index(_index), chart(new QChart), series(new QLineSeries), xaxis(new QValueAxis), yaxis(new QValueAxis) { chart->legend()->hide(); - chart->addAxis(xaxis,Qt::AlignBottom); - chart->addAxis(yaxis,Qt::AlignLeft); + chart->addAxis(xaxis, Qt::AlignBottom); + chart->addAxis(yaxis, Qt::AlignLeft); chart->addSeries(series); series->attachAxis(xaxis); series->attachAxis(yaxis); @@ -33,22 +110,17 @@ ChartViewer::ChartViewer(QWidget *parent) : yaxis->setTickCount(5); xaxis->setMinorTickCount(5); yaxis->setMinorTickCount(5); + yaxis->setTitleText(title); + series->setName(title); setRenderHint(QPainter::Antialiasing); setChart(chart); setRubberBand(QChartView::RectangleRubberBand); - - QSettings settings; - resize(settings.value("chartx", 500).toInt(), settings.value("charty", 320).toInt()); } -void ChartViewer::add_column(const QString &title) -{ - yaxis->setTitleText(title); - series->setName(title); -} +/* -------------------------------------------------------------------- */ -void ChartViewer::add_data(int step, int column, double data) +void ChartViewer::add_data(int step, double data) { if (last_step < step) { last_step = step; @@ -70,16 +142,6 @@ void ChartViewer::add_data(int step, int column, double data) } } -void ChartViewer::closeEvent(QCloseEvent *event) -{ - QSettings settings; - if (!isMaximized()) { - settings.setValue("chartx", width()); - settings.setValue("charty", height()); - } - QChartView::closeEvent(event); -} - // Local Variables: // c-basic-offset: 4 // End: diff --git a/tools/lammps-gui/chartviewer.h b/tools/lammps-gui/chartviewer.h index 2ee95788fc..196faa4f95 100644 --- a/tools/lammps-gui/chartviewer.h +++ b/tools/lammps-gui/chartviewer.h @@ -14,23 +14,61 @@ #ifndef CHARTVIEWER_H #define CHARTVIEWER_H +#include +#include +#include #include -class ChartViewer : public QtCharts::QChartView { +class QAction; +class QMenuBar; +class QMenu; +class QComboBox; +class ChartViewer; + +class ChartWindow : public QWidget { Q_OBJECT public: - ChartViewer(QWidget *parent = nullptr); - bool has_columns() const { return last_step >= 0; } - void add_column(const QString &title); - void add_data(int step, int column, double data); - int get_last_step() const; + ChartWindow(const QString &filename, QWidget *parent = nullptr); + + bool has_charts() const { return !charts.isEmpty(); } + void add_chart(const QString &title, int index); + void add_data(int step, double data, int index); + +private slots: + void saveAs(); + void change_chart(int index); + + // void normalSize(); protected: void closeEvent(QCloseEvent *event) override; private: - int last_step; + QMenuBar *menu; + QMenu *file; + QComboBox *columns; + QAction *saveAsAct; + QAction *closeAct; + + QString filename; + int active_chart; + QList charts; +}; + +/* -------------------------------------------------------------------- */ + +class ChartViewer : public QtCharts::QChartView { + Q_OBJECT + +public: + explicit ChartViewer(const QString &title, int index, QWidget *parent = nullptr); + + void add_data(int step, double data); + int get_index() const { return index; }; + +private: + int last_step, index; QtCharts::QChart *chart; QtCharts::QLineSeries *series; QtCharts::QValueAxis *xaxis; diff --git a/tools/lammps-gui/lammpsgui.cpp b/tools/lammps-gui/lammpsgui.cpp index 964215ac1c..199c114eb5 100644 --- a/tools/lammps-gui/lammpsgui.cpp +++ b/tools/lammps-gui/lammpsgui.cpp @@ -414,15 +414,26 @@ void LammpsGui::logupdate() else step = (int)*(int64_t *)ptr; int ncols = *(int *)lammps.last_thermo("num", 0); - if (!chartwindow->has_columns()) { - // for (int i = 0; i < ncols; ++i) { - chartwindow->add_column((const char *)lammps.last_thermo("keyword", 1)); - // } + if (!chartwindow->has_charts()) { + for (int i = 0; i < ncols; ++i) { + QString label = (const char *)lammps.last_thermo("keyword", i); + // no need to store the timestep column + if (label == "Step") continue; + chartwindow->add_chart(label, i); + } } - // for (int i = 0; i < ncols; ++i) { - chartwindow->add_data(step, 0, *(double *)lammps.last_thermo("data", 1)); - // } + for (int i = 0; i < ncols; ++i) { + int datatype = *(int *)lammps.last_thermo("type", i); + double data; + if (datatype == 0) // int + data = *(int *)lammps.last_thermo("data", i); + else if (datatype == 2) // double + data = *(double *)lammps.last_thermo("data", i); + else if (datatype == 4) // bigint + data = (double)*(int64_t *)lammps.last_thermo("data", i); + chartwindow->add_data(step, data, i); + } } } } @@ -458,18 +469,26 @@ void LammpsGui::run_done() else step = (int)*(int64_t *)ptr; int ncols = *(int *)lammps.last_thermo("num", 0); - if (!chartwindow->has_columns()) { - // for (int i = 0; i < ncols; ++i) { - chartwindow->add_column((const char *)lammps.last_thermo("keyword", 1)); - // } + for (int i = 0; i < ncols; ++i) { + if (!chartwindow->has_charts()) { + QString label = (const char *)lammps.last_thermo("keyword", i); + // no need to store the timestep column + if (label == "Step") continue; + chartwindow->add_chart(label, i); + } + int datatype = *(int *)lammps.last_thermo("type", i); + double data; + if (datatype == 0) // int + data = *(int *)lammps.last_thermo("data", i); + else if (datatype == 2) // double + data = *(double *)lammps.last_thermo("data", i); + else if (datatype == 4) // bigint + data = (double)*(int64_t *)lammps.last_thermo("data", i); + chartwindow->add_data(step, data, i); } - - // for (int i = 0; i < ncols; ++i) { - chartwindow->add_data(step, 0, *(double *)lammps.last_thermo("data", 1)); - // } } } - + bool success = true; constexpr int BUFLEN = 1024; char errorbuf[BUFLEN]; @@ -552,13 +571,13 @@ void LammpsGui::run_buffer() // if configured, delete old log window before opening new one if (settings.value("chartreplace", false).toBool()) delete chartwindow; - chartwindow = new ChartViewer(); + chartwindow = new ChartWindow(current_file); chartwindow->setWindowTitle("LAMMPS-GUI - Thermo charts from running LAMMPS on buffer - " + current_file); chartwindow->setWindowIcon(QIcon(":/lammps-icon-128x128.png")); chartwindow->setMinimumSize(400, 300); shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), chartwindow); - QObject::connect(shortcut, &QShortcut::activated, chartwindow, &ChartViewer::close); + QObject::connect(shortcut, &QShortcut::activated, chartwindow, &ChartWindow::close); shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Slash), chartwindow); QObject::connect(shortcut, &QShortcut::activated, this, &LammpsGui::stop_run); chartwindow->show(); diff --git a/tools/lammps-gui/lammpsgui.h b/tools/lammps-gui/lammpsgui.h index 158e4e86ac..a36dca2757 100644 --- a/tools/lammps-gui/lammpsgui.h +++ b/tools/lammps-gui/lammpsgui.h @@ -39,7 +39,7 @@ class Highlighter; class StdCapture; class Preferences; class ImageViewer; -class ChartViewer; +class ChartWindow; class LammpsGui : public QMainWindow { Q_OBJECT @@ -86,7 +86,7 @@ private: QLabel *status; QPlainTextEdit *logwindow; ImageViewer *imagewindow; - ChartViewer *chartwindow; + ChartWindow *chartwindow; QTimer *logupdater; QLabel *dirstatus; QProgressBar *progress;