Build Packages / Create release (push) Successful in 24s
Build Packages / build:viewer:macos-arm64:nocuda (push) Successful in 3m29s
Build Packages / build:rugnux:macos-arm64:nocuda (push) Successful in 2m43s
Build Packages / build:rugnux:linux-aarch64:cuda (push) Successful in 8m27s
Build Packages / build:rugnux:linux-x86_64:cuda (push) Successful in 9m53s
Build Packages / build:viewer:linux-x86_64:nocuda (push) Successful in 9m58s
Build Packages / build:viewer:linux-x86_64:cuda (push) Successful in 11m22s
Build Packages / build:jfjoch:rocky8:nocuda (push) Successful in 13m39s
Build Packages / build:viewer:windows-x86_64:nocuda (push) Successful in 18m37s
Build Packages / build:jfjoch:rocky9:nocuda (push) Successful in 16m32s
Build Packages / build:viewer:windows-x86_64:cuda (push) Successful in 24m11s
Build Packages / HDF5 consumer tests (DIALS, XDS) (push) Successful in 25m30s
Build Packages / build:jfjoch:ubuntu2404:nocuda (push) Successful in 19m3s
Build Packages / build:jfjoch:ubuntu2204:nocuda (push) Successful in 20m23s
Build Packages / build:jfjoch:rocky8:cuda-sls9 (push) Successful in 19m41s
Build Packages / Generate python client (push) Successful in 50s
Build Packages / Build documentation (push) Successful in 1m16s
Build Packages / build:jfjoch:rocky9:cuda-sls9 (push) Successful in 21m0s
Build Packages / build:jfjoch:rocky8:cuda (push) Successful in 18m38s
Build Packages / build:rugnux:windows-x86_64:cuda (push) Successful in 14m33s
Build Packages / build:jfjoch:rocky9:cuda (push) Successful in 17m55s
Build Packages / build:jfjoch:ubuntu2204:cuda (push) Successful in 20m50s
Build Packages / build:jfjoch:ubuntu2404:cuda (push) Successful in 18m38s
Build Packages / Unit tests (push) Successful in 1h46m14s
* jfjoch_broker: Optional per-dataset authentication - statistics, images and plots can require a bearer token, which jfjoch_viewer supports. * jfjoch_viewer: Dark mode and a theme-matched colour scheme, a magnifier panel, and simpler contrast and background controls. * Rugnux: Multiple performance improvements on GPU and CPU (CPU-only processing up to 40% faster, faster image decoding on ARM), with unchanged results. * Rugnux: `--model` rigid-body refinement runs on the GPU, and the model-validation check is faster and more reliable. * Rugnux: Improved scaling and merging - error model, outlier rejection, absorption correction and French-Wilson amplitudes now agree more closely with XDS and ctruncate. * Rugnux: Improved integration - radial background on powder and ice rings, crowded rotation data keep their reflections, and CPU-only builds integrate large unit cells as GPU builds do. * Rugnux: More robust detector geometry - measured beam centre, X-ray bandwidth and goniometer rate, and geometry refinement accepted only on significant evidence. * Rugnux: Merged files are written in the standard setting, or in the setting of a reference MTZ, structure-factor mmCIF or model, with its free-R flags. * Rugnux: Richer report - ice and powder rings, further lattices, superstructure candidates and mosaicity, with warnings worded as prompts to check. * Rugnux: Clear error messages when a data set needs more GPU or host memory than is available. Reviewed-on: #83 Co-authored-by: Filip Leonarski <filip.leonarski@psi.ch>
136 lines
6.6 KiB
C++
136 lines
6.6 KiB
C++
// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute <filip.leonarski@psi.ch>
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
#pragma once
|
|
|
|
#include <QElapsedTimer>
|
|
#include <QMainWindow>
|
|
#include <QProgressDialog>
|
|
#include <QTimer>
|
|
|
|
#include "JFJochViewerMenu.h"
|
|
#include "../reader/JFJochHDF5Reader.h"
|
|
#include "JFJochImageReadingWorker.h"
|
|
#include "JFJochViewerDatasetInfo.h"
|
|
#include "JFJochViewerStatusBar.h"
|
|
#include "toolbar/JFJochViewerToolbarDisplay.h"
|
|
|
|
class JFJochProcessingJobsWindow;
|
|
class JFJochDiffractionImage;
|
|
class JFJochHelperWindow;
|
|
class JFJochViewerMagnifier;
|
|
class QDockWidget;
|
|
class QScrollArea;
|
|
|
|
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;
|
|
JFJochDiffractionImage *viewer; // central diffraction image
|
|
JFJochViewerToolbarDisplay *toolBarDisplay;
|
|
JFJochViewerStatusBar *statusbar;
|
|
JFJochProcessingJobsWindow *processingJobsWindow;
|
|
|
|
std::shared_ptr<const JFJochReaderDataset> lastDataset; // added
|
|
std::shared_ptr<const JFJochReaderImage> lastImage; // added
|
|
|
|
// Remote-display frame throttle (see OnImageReady): the newest frame not yet fanned out,
|
|
// delivered at most every kRemoteRepaintIntervalMs while a fast producer runs.
|
|
std::shared_ptr<const JFJochReaderImage> pendingImage;
|
|
QElapsedTimer image_rate_;
|
|
QTimer *image_tail_timer_ = nullptr;
|
|
void DeliverPendingImage();
|
|
QVector<RunData> 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)
|
|
QScrollArea *inspectorScroll = nullptr; // its scroll area; width bounds follow the font
|
|
QDockWidget *settingsDock = nullptr; // inline MX/AzInt settings panel
|
|
QDockWidget *fileBrowserDock = nullptr; // data-root directory tree, tabbed with settingsDock
|
|
QDockWidget *processingDock = nullptr; // processing jobs panel
|
|
JFJochViewerMagnifier *magnifier = nullptr;
|
|
QDockWidget *magnifierDock = nullptr; // where the magnifier normally sits
|
|
JFJochHelperWindow *magnifierWindow = nullptr; // ... and its window when popped out
|
|
void PopOutMagnifier();
|
|
QByteArray defaultLayoutState; // captured after construction, for "Reset layout"
|
|
int datasetInfoCounter = 0; // gives each dataset-info dock a unique objectName
|
|
|
|
void ResetAllSettings();
|
|
void UpdateInspectorWidth();
|
|
|
|
// A narrow window folds the inspector away (with the magnifier, when it is docked in the same
|
|
// column) so the image keeps its room, and brings it back once the window is wide enough again.
|
|
QList<QDockWidget *> autoHiddenDocks; // hidden by the window, not by the user
|
|
int autoHiddenWidth = 0; // the inspector column's width when it was folded away
|
|
void resizeEvent(QResizeEvent *event) override;
|
|
|
|
// Both ways of opening a dataset from outside the file manager - the File menu and D-Bus -
|
|
// come through here, so the browser follows the same way for either.
|
|
void FollowInFileBrowser(const QString &filename);
|
|
|
|
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);
|
|
|
|
// Keyboard shortcuts (F/B/A, Home/End/PageUp/PageDown) are handled in an application-wide
|
|
// event filter rather than keyPressEvent, so they work wherever the focus happens to be,
|
|
// stepping aside when the focused widget genuinely uses the key (text entry, item views).
|
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
|
void closeEvent(QCloseEvent *event) override;
|
|
void changeEvent(QEvent *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<const JFJochReaderImage> 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<const JFJochReaderDataset> dataset);
|
|
|
|
public slots:
|
|
void LoadFile(const QString &filename, qint64 image_number, qint64 summation, bool retry);
|
|
void LoadImage(qint64 image_number, qint64 summation);
|
|
// The bearer token for a protected broker dataset. Sources, each overriding the previous:
|
|
// JUNGFRAUJOCH_HTTP_TOKEN at start-up, D-Bus, the Open HTTP Connection dialog.
|
|
void SetHttpToken(const QString &token);
|
|
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<const JFJochReaderImage> 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<const JFJochReaderDataset> 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 HttpTokenRequest(QString token);
|
|
void adjustForegroundButton(bool input);
|
|
void adjustBackgroundButton(bool input);
|
|
void setAutoForeground(bool val);
|
|
void oneShotAutoForeground();
|
|
// Re-emitted by the shortcut filter; the navigation toolbar applies the step, clamped.
|
|
void stepImage(int steps);
|
|
};
|
|
|