diff options
Diffstat (limited to 'gui')
-rw-r--r-- | gui/base.qrc | 2 | ||||
-rw-r--r-- | gui/basewindow.cc | 50 | ||||
-rw-r--r-- | gui/basewindow.h | 6 | ||||
-rw-r--r-- | gui/fpgaviewwidget.cc | 38 | ||||
-rw-r--r-- | gui/fpgaviewwidget.h | 8 | ||||
-rw-r--r-- | gui/resources/camera.png | bin | 0 -> 665 bytes | |||
-rw-r--r-- | gui/resources/film.png | bin | 0 -> 653 bytes |
7 files changed, 102 insertions, 2 deletions
diff --git a/gui/base.qrc b/gui/base.qrc index 63612bf4..0671fa9e 100644 --- a/gui/base.qrc +++ b/gui/base.qrc @@ -28,5 +28,7 @@ <file>resources/wire.png</file> <file>resources/pip.png</file> <file>resources/group.png</file> + <file>resources/camera.png</file> + <file>resources/film.png</file> </qresource> </RCC> diff --git a/gui/basewindow.cc b/gui/basewindow.cc index c3dbc131..0bfc59a3 100644 --- a/gui/basewindow.cc +++ b/gui/basewindow.cc @@ -23,6 +23,7 @@ #include <QFileDialog>
#include <QGridLayout>
#include <QIcon>
+#include <QImageWriter>
#include <QInputDialog>
#include <QSplitter>
#include <fstream>
@@ -252,6 +253,18 @@ void BaseMainWindow::createMenusAndBars() actionDisplayGroups->setChecked(true);
connect(actionDisplayGroups, &QAction::triggered, this, &BaseMainWindow::enableDisableDecals);
+ actionScreenshot = new QAction("Screenshot", this);
+ actionScreenshot->setIcon(QIcon(":/icons/resources/camera.png"));
+ actionScreenshot->setStatusTip("Taking a screenshot");
+ connect(actionScreenshot, &QAction::triggered, this, &BaseMainWindow::screenshot);
+
+ actionMovie = new QAction("Recording", this);
+ actionMovie->setIcon(QIcon(":/icons/resources/film.png"));
+ actionMovie->setStatusTip("Saving a movie");
+ actionMovie->setCheckable(true);
+ actionMovie->setChecked(false);
+ connect(actionMovie, &QAction::triggered, this, &BaseMainWindow::saveMovie);
+
// set initial state
fpgaView->enableDisableDecals(actionDisplayBel->isChecked(), actionDisplayWire->isChecked(),
actionDisplayPip->isChecked(), actionDisplayGroups->isChecked());
@@ -317,6 +330,9 @@ void BaseMainWindow::createMenusAndBars() deviceViewToolBar->addAction(actionDisplayWire);
deviceViewToolBar->addAction(actionDisplayPip);
deviceViewToolBar->addAction(actionDisplayGroups);
+ deviceViewToolBar->addSeparator();
+ deviceViewToolBar->addAction(actionScreenshot);
+ deviceViewToolBar->addAction(actionMovie);
// Add status bar with progress bar
statusBar = new QStatusBar();
@@ -362,6 +378,40 @@ void BaseMainWindow::save_json() }
}
+void BaseMainWindow::screenshot()
+{
+ QString fileName = QFileDialog::getSaveFileName(this, QString("Save screenshot"), QString(), QString("*.png"));
+ if (!fileName.isEmpty()) {
+ QImage image = fpgaView->grabFramebuffer();
+ if (!fileName.endsWith(".png"))
+ fileName += ".png";
+ QImageWriter imageWriter(fileName, "png");
+ if (imageWriter.write(image))
+ log("Saving screenshot successful.\n");
+ else
+ log("Saving screenshot failed.\n");
+ }
+}
+
+void BaseMainWindow::saveMovie()
+{
+ if (actionMovie->isChecked()) {
+ QString dir = QFileDialog::getExistingDirectory(this, tr("Select Movie Directory"), QDir::currentPath(),
+ QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks);
+ if (!dir.isEmpty()) {
+ bool ok;
+ int frames = QInputDialog::getInt(this, "Skip frames", tr("Frames to skip (1 frame = 50ms):"), 5, 0, 1000,
+ 1, &ok);
+ if (ok)
+ fpgaView->movieStart(dir, frames);
+ else
+ actionMovie->setChecked(false);
+ } else
+ actionMovie->setChecked(false);
+ } else {
+ fpgaView->movieStop();
+ }
+}
void BaseMainWindow::pack_finished(bool status)
{
disableActions();
diff --git a/gui/basewindow.h b/gui/basewindow.h index 7562307e..fe9dfdf2 100644 --- a/gui/basewindow.h +++ b/gui/basewindow.h @@ -83,6 +83,9 @@ class BaseMainWindow : public QMainWindow void taskStarted();
void taskPaused();
+ void screenshot();
+ void saveMovie();
+
Q_SIGNALS:
void contextChanged(Context *ctx);
void updateTreeView();
@@ -128,6 +131,9 @@ class BaseMainWindow : public QMainWindow QAction *actionDisplayWire;
QAction *actionDisplayPip;
QAction *actionDisplayGroups;
+
+ QAction *actionScreenshot;
+ QAction *actionMovie;
};
NEXTPNR_NAMESPACE_END
diff --git a/gui/fpgaviewwidget.cc b/gui/fpgaviewwidget.cc index 2e1bbf63..8730c9d9 100644 --- a/gui/fpgaviewwidget.cc +++ b/gui/fpgaviewwidget.cc @@ -22,6 +22,9 @@ #include <QApplication> #include <QCoreApplication> +#include <QDir> +#include <QFileInfo> +#include <QImageWriter> #include <QMouseEvent> #include <QWidget> @@ -35,7 +38,7 @@ NEXTPNR_NAMESPACE_BEGIN FPGAViewWidget::FPGAViewWidget(QWidget *parent) - : QOpenGLWidget(parent), ctx_(nullptr), paintTimer_(this), lineShader_(this), zoom_(10.0f), + : QOpenGLWidget(parent), movieSaving(false), ctx_(nullptr), paintTimer_(this), lineShader_(this), zoom_(10.0f), rendererArgs_(new FPGAViewWidget::RendererArgs), rendererData_(new FPGAViewWidget::RendererData) { colors_.background = QColor("#000000"); @@ -322,6 +325,23 @@ void FPGAViewWidget::paintGL() lineShader_.draw(GraphicElement::STYLE_SELECTED, colors_.selected, thick11Px, matrix); lineShader_.draw(GraphicElement::STYLE_HOVER, colors_.hovered, thick2Px, matrix); + if (movieSaving) { + if (movieCounter == currentFrameSkip) { + QMutexLocker lock(&rendererArgsLock_); + movieCounter = 0; + currentMovieFrame++; + + QImage image = grabFramebuffer(); + QString number = QString("movie_%1.png").arg(currentMovieFrame, 5, 10, QChar('0')); + + QFileInfo fileName = QFileInfo(QDir(movieDir), number); + QImageWriter imageWriter(fileName.absoluteFilePath(), "png"); + imageWriter.write(image); + } else { + movieCounter++; + } + } + // Render ImGui QtImGui::newFrame(); QMutexLocker lock(&rendererArgsLock_); @@ -579,6 +599,22 @@ void FPGAViewWidget::renderLines(void) } } +void FPGAViewWidget::movieStart(QString dir, long frameSkip) +{ + QMutexLocker locker(&rendererArgsLock_); + movieDir = dir; + currentMovieFrame = 0; + movieCounter = 0; + currentFrameSkip = frameSkip; + movieSaving = true; +} + +void FPGAViewWidget::movieStop() +{ + QMutexLocker locker(&rendererArgsLock_); + movieSaving = false; +} + void FPGAViewWidget::onSelectedArchItem(std::vector<DecalXY> decals, bool keep) { { diff --git a/gui/fpgaviewwidget.h b/gui/fpgaviewwidget.h index 735590ba..7f99408e 100644 --- a/gui/fpgaviewwidget.h +++ b/gui/fpgaviewwidget.h @@ -120,13 +120,19 @@ class FPGAViewWidget : public QOpenGLWidget, protected QOpenGLFunctions void zoomSelected(); void zoomOutbound(); void enableDisableDecals(bool bels, bool wires, bool pips, bool groups); - + void movieStart(QString dir, long frameSkip); + void movieStop(); Q_SIGNALS: void clickedBel(BelId bel, bool add); void clickedWire(WireId wire, bool add); void clickedPip(PipId pip, bool add); private: + QString movieDir; + long currentMovieFrame; + long currentFrameSkip; + long movieCounter; + bool movieSaving; const float zoomNear_ = 0.05f; // do not zoom closer than this float zoomFar_ = 10.0f; // do not zoom further than this const float zoomLvl1_ = 1.0f; diff --git a/gui/resources/camera.png b/gui/resources/camera.png Binary files differnew file mode 100644 index 00000000..8536d1a7 --- /dev/null +++ b/gui/resources/camera.png diff --git a/gui/resources/film.png b/gui/resources/film.png Binary files differnew file mode 100644 index 00000000..b0ce7bb1 --- /dev/null +++ b/gui/resources/film.png |