// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include "JFJochViewerMenu.h" #include "../reader/JFJochHDF5Reader.h" #include "JFJochImageReadingWorker.h" #include "JFJochViewerDatasetInfo.h" #include "JFJochViewerStatusBar.h" #include "toolbar/JFJochViewerToolbarDisplay.h" class JFJochProcessingJobsWindow; class QDockWidget; class JFJochViewerWindow : public QMainWindow { Q_OBJECT // Theming is done via the application palette in main() (salmon panels, white entry fields, // navy accent) so it applies consistently to every widget, including dialogs. public: explicit JFJochViewerWindow(QWidget *parent = nullptr, bool dbus = true, const QString &file = ""); ~JFJochViewerWindow() override; private: JFJochViewerMenu *menuBar; JFJochImageReadingWorker *reading_worker; JFJochViewerToolbarDisplay *toolBarDisplay; JFJochViewerStatusBar *statusbar; JFJochProcessingJobsWindow *processingJobsWindow; std::shared_ptr lastDataset; // added std::shared_ptr lastImage; // added QVector lastRuns; // for dataset-info docks opened later QString lastActiveRunId; QProgressDialog *retryDialog = nullptr; QDockWidget *lastDatasetInfoDock = nullptr; // most recent dataset-info dock, for docking layout QDockWidget *inspectorDock = nullptr; // image inspector (former right-hand side panel) QDockWidget *settingsDock = nullptr; // inline MX/AzInt settings panel QDockWidget *processingDock = nullptr; // processing jobs panel QDockWidget *imageStripDock = nullptr; // thumbnail strip / hit feed QByteArray defaultLayoutState; // captured after construction, for "Reset layout" int datasetInfoCounter = 0; // gives each dataset-info dock a unique objectName QThread *reading_thread; // Named layouts. Image = just the image + inspector; Processing = also the plots + jobs panel. enum class Perspective { Image, Processing }; void ApplyPerspective(Perspective p); void keyPressEvent(QKeyEvent *event) override; void keyReleaseEvent(QKeyEvent *event) override; void closeEvent(QCloseEvent *event) override; private slots: // Single cross-thread sink for the worker's imageLoaded: fans out to every GUI consumer // (synchronously, same thread) via imageReady, then acks the worker so it may produce the next. void OnImageReady(std::shared_ptr image); // Single cross-thread sink for the worker's datasetLoaded, mirroring OnImageReady: fans out to // every GUI consumer synchronously via datasetReady, then acks the worker (datasetConsumed) so the // worker can cap how many datasets are in flight - without this the queued datasetLoaded backlog // (each event pinning a full dataset) grew without bound in live follow (100 GB OOM). void OnDatasetReady(std::shared_ptr dataset); public slots: void LoadFile(const QString &filename, qint64 image_number, qint64 summation, bool retry); void LoadImage(qint64 image_number, qint64 summation); void NewDatasetInfo(); void OnFileLoadError(QString title, QString message); void OnFileLoadRetryStatus(bool active, QString message); signals: // Internal GUI-thread fan-out of the newest frame: OnImageReady re-emits this to every GUI // consumer synchronously, then acks via imageConsumed (see OnImageReady). void imageReady(std::shared_ptr image); void imageConsumed(); // ack to the worker that one frame has been consumed (backpressure) // Same GUI-thread fan-out + ack for the dataset stream (see OnDatasetReady). void datasetReady(std::shared_ptr dataset); void datasetConsumed(); // ack to the worker that one dataset has been consumed (backpressure) void LoadFileRequest(const QString &filename, qint64 image_number, qint64 summation, bool retry); void LoadImageRequest(int64_t image_number, int64_t summation); void adjustForegroundButton(bool input); void setAutoForeground(bool val); };