// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochViewerWindow.h" #include #include #include #include "JFJochImageReadingWorker.h" #include "image_viewer/JFJochDiffractionImage.h" #include "JFJochViewerSidePanel.h" #include "JFJochViewerStatusBar.h" #include "../common/CUDAWrapper.h" #include "windows/JFJochViewerImageListWindow.h" #include "windows/JFJochViewerMetadataWindow.h" #include "dbus/JFJochViewerAdaptor.h" #include "windows/JFJochViewerProcessingWindow.h" #include "windows/JFJochViewerSpotListWindow.h" #include "windows/JFJochViewerReflectionListWindow.h" #include "windows/JFJochCalibrationWindow.h" #include "toolbar/JFJochViewerToolbarDisplay.h" #include "toolbar/JFJochViewerToolbarImage.h" #include "windows/JFJoch2DAzintImageWindow.h" #include "windows/JFJochAzIntWindow.h" JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString &file) : QMainWindow(parent) { menuBar = new JFJochViewerMenu(this); setMenuBar(menuBar); auto toolBarImage = new JFJochViewerToolbarImage(this); addToolBar(Qt::TopToolBarArea, toolBarImage); addToolBarBreak(Qt::TopToolBarArea); toolBarDisplay = new JFJochViewerToolbarDisplay(this); addToolBar(Qt::TopToolBarArea, toolBarDisplay); statusbar = new JFJochViewerStatusBar(this); setStatusBar(statusbar); setDockOptions(dockOptions() & ~QMainWindow::DockOption::AllowTabbedDocks); setStyleSheet(stylesheet); setWindowTitle("Jungfraujoch image viewer"); resize(1200, 1200); SpotFindingSettings spot_finding_settings = DiffractionExperiment::DefaultDataProcessingSettings(); spot_finding_settings.high_resolution_limit = 1.5; spot_finding_settings.indexing = true; IndexingSettings indexing_settings; indexing_settings.IndexingThreads(1); indexing_settings.Algorithm(IndexingAlgorithmEnum::Auto); if (get_gpu_count() == 0) { indexing_settings.Algorithm(IndexingAlgorithmEnum::FFTW); indexing_settings.FFT_NumVectors(8 * 1024); } indexing_settings.GeomRefinementAlgorithm(GeomRefinementAlgorithmEnum::BeamCenter); DiffractionExperiment experiment; experiment.ImportIndexingSettings(indexing_settings); experiment.DetectIceRings(true); // Central area: only the main horizontal splitter (image + side panel) auto h_splitter = new QSplitter(this); h_splitter->setOrientation(Qt::Horizontal); setCentralWidget(h_splitter); auto viewer = new JFJochDiffractionImage(this); viewer->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding); h_splitter->addWidget(viewer); auto side_panel = new JFJochViewerSidePanel(this); auto side_panel_scroll = new QScrollArea(this); side_panel_scroll->setWidget(side_panel); side_panel_scroll->setWidgetResizable(true); side_panel_scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); side_panel_scroll->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded); side_panel_scroll->setMinimumWidth(450); side_panel_scroll->setMaximumWidth(600); side_panel_scroll->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); h_splitter->addWidget(side_panel_scroll); reading_worker = new JFJochImageReadingWorker(spot_finding_settings, experiment); reading_thread = new QThread(this); reading_worker->moveToThread(reading_thread); reading_thread->start(); auto tableWindow = new JFJochViewerImageListWindow(this); auto metadataWindow = new JFJochViewerMetadataWindow(this); auto spotWindow = new JFJochViewerSpotListWindow(this); auto reflectionWindow = new JFJochViewerReflectionListWindow(this); auto processingWindow = new JFJochViewerProcessingWindow(spot_finding_settings, indexing_settings, this); auto calibrationWindow = new JFJochCalibrationWindow(this); auto azintWindow = new JFJochAzIntWindow(experiment.GetAzimuthalIntegrationSettings(), this); auto azintImageWindow = new JFJoch2DAzintImageWindow(this); menuBar->AddWindowEntry(tableWindow, "Image list"); menuBar->AddWindowEntry(spotWindow, "Spot list"); menuBar->AddWindowEntry(reflectionWindow, "Reflection list"); menuBar->AddWindowEntry(metadataWindow, "Image metadata"); menuBar->AddWindowEntry(processingWindow, "Image processing settings"); menuBar->AddWindowEntry(calibrationWindow, "Calibration image viewer"); menuBar->AddWindowEntry(azintWindow, "Azimuthal integration settings"); menuBar->AddWindowEntry(azintImageWindow, "Azimuthal integration 2D image"); if (dbus) { // Create adaptor attached to this window new JFJochViewerAdaptor(this); QDBusConnection connection = QDBusConnection::sessionBus(); if (!connection.registerService("ch.psi.jfjoch_viewer")) { qWarning("Failed to register D-Bus service: %s", qPrintable(connection.lastError().message())); } else { if (!connection.registerObject("/", this, QDBusConnection::ExportAdaptors)) { qFatal("Failed to register D-Bus object: %s", qPrintable(connection.lastError().message())); } } } connect(this, &JFJochViewerWindow::LoadFileRequest, reading_worker, &JFJochImageReadingWorker::LoadFile); connect(this, &JFJochViewerWindow::LoadImageRequest, reading_worker, &JFJochImageReadingWorker::LoadImage); connect(menuBar, &JFJochViewerMenu::fileOpenSelected, reading_worker, &JFJochImageReadingWorker::LoadFile); connect(menuBar, &JFJochViewerMenu::fileCloseSelected, reading_worker, &JFJochImageReadingWorker::CloseFile); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, viewer, &JFJochDiffractionImage::loadImage); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, side_panel, &JFJochViewerSidePanel::loadImage); connect(reading_worker, &JFJochImageReadingWorker::imageStatsUpdated, side_panel, &JFJochViewerSidePanel::loadImage); connect(reading_worker, &JFJochImageReadingWorker::imageNumberChanged, toolBarImage, &JFJochViewerToolbarImage::setImageNumber); connect(toolBarImage, &JFJochViewerToolbarImage::loadImage, reading_worker, &JFJochImageReadingWorker::LoadImage); connect(toolBarDisplay, &JFJochViewerToolbarDisplay::setForeground, viewer, &JFJochDiffractionImage::changeForeground); connect(viewer, &JFJochDiffractionImage::autoForegroundChanged, toolBarDisplay, &JFJochViewerToolbarDisplay::updateAutoForeground); connect(toolBarDisplay, &JFJochViewerToolbarDisplay::setAutoForeground, viewer, &JFJochDiffractionImage::setAutoForeground); connect(toolBarDisplay, &JFJochViewerToolbarDisplay::colorMapChanged, viewer, &JFJochDiffractionImage::setColorMap); connect(toolBarDisplay, &JFJochViewerToolbarDisplay::colorMapChanged, azintImageWindow, &JFJoch2DAzintImageWindow::setColorMap); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, azintImageWindow, &JFJoch2DAzintImageWindow::imageLoaded); connect(viewer, &JFJochDiffractionImage::foregroundChanged, toolBarDisplay, &JFJochViewerToolbarDisplay::updateForeground); connect(viewer, &JFJochDiffractionImage::roiBoxUpdated, reading_worker, &JFJochImageReadingWorker::SetROIBox); connect(viewer, &JFJochDiffractionImage::roiCircleUpdated, reading_worker, &JFJochImageReadingWorker::SetROICircle); connect(viewer, &JFJochDiffractionImage::roiBoxUpdated, side_panel, &JFJochViewerSidePanel::SetROIBox); connect(viewer, &JFJochDiffractionImage::roiCircleUpdated, side_panel, &JFJochViewerSidePanel::SetROICircle); connect(viewer, &JFJochDiffractionImage::roiCalculated, side_panel, &JFJochViewerSidePanel::SetROIResult); connect(side_panel, &JFJochViewerSidePanel::ROIBoxConfigured, reading_worker, &JFJochImageReadingWorker::SetROIBox); connect(side_panel, &JFJochViewerSidePanel::ROICircleConfigured, reading_worker, &JFJochImageReadingWorker::SetROICircle); connect(side_panel, &JFJochViewerSidePanel::ROIBoxConfigured, viewer, &JFJochDiffractionImage::SetROIBox); connect(side_panel, &JFJochViewerSidePanel::ROICircleConfigured, viewer, &JFJochDiffractionImage::SetROICircle); connect(side_panel, &JFJochViewerSidePanel::AddROIToUserMask, reading_worker, &JFJochImageReadingWorker::AddROIToUserMask); connect(side_panel, &JFJochViewerSidePanel::SubtractROIFromUserMask, reading_worker, &JFJochImageReadingWorker::SubtractROIFromUserMask); connect(menuBar, &JFJochViewerMenu::clearUserMaskSelected, reading_worker, &JFJochImageReadingWorker::ClearUserMask); connect(menuBar, &JFJochViewerMenu::saveUserMaskTiffSelected, reading_worker, &JFJochImageReadingWorker::SaveUserMaskTIFF); connect(menuBar, &JFJochViewerMenu::uploadUserMaskSelected, reading_worker, &JFJochImageReadingWorker::UploadUserMask); connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, tableWindow, &JFJochViewerImageListWindow::datasetLoaded); connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, spotWindow, &JFJochViewerSpotListWindow::datasetLoaded); connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, metadataWindow, &JFJochViewerMetadataWindow::datasetLoaded); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, tableWindow, &JFJochViewerImageListWindow::imageLoaded); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, spotWindow, &JFJochViewerSpotListWindow::imageLoaded); connect(tableWindow, &JFJochViewerImageListWindow::imageSelected, reading_worker, &JFJochImageReadingWorker::LoadImage); connect(reading_worker, &JFJochImageReadingWorker::autoloadChanged, toolBarImage, &JFJochViewerToolbarImage::setAutoloadMode); connect(toolBarImage, &JFJochViewerToolbarImage::autoLoadButtonPressed, reading_worker, &JFJochImageReadingWorker::setAutoLoadMode); connect(toolBarImage, &JFJochViewerToolbarImage::imageJumpChanged, reading_worker, &JFJochImageReadingWorker::setAutoLoadJump); connect(toolBarImage, &JFJochViewerToolbarImage::reanalyzeImages, reading_worker, &JFJochImageReadingWorker::ReanalyzeImages); connect(side_panel, &JFJochViewerSidePanel::analyze, reading_worker, &JFJochImageReadingWorker::Analyze); connect(side_panel, &JFJochViewerSidePanel::findBeamCenter, reading_worker, &JFJochImageReadingWorker::FindCenter); connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, reflectionWindow, &JFJochViewerReflectionListWindow::datasetLoaded); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, reflectionWindow, &JFJochViewerReflectionListWindow::imageLoaded); connect(processingWindow, &JFJochViewerProcessingWindow::settingsChanged, reading_worker, &JFJochImageReadingWorker::UpdateSpotFindingSettings); connect(reflectionWindow, &JFJochHelperWindow::zoom, viewer, &JFJochDiffractionImage::centerOnSpot); connect(spotWindow, &JFJochHelperWindow::zoom, viewer, &JFJochDiffractionImage::centerOnSpot); connect(side_panel, &JFJochViewerSidePanel::showSpots, viewer, &JFJochDiffractionImage::showSpots); connect(side_panel, &JFJochViewerSidePanel::showPredictions, viewer, &JFJochDiffractionImage::showPredictions); connect(side_panel, &JFJochViewerSidePanel::setFeatureColor, viewer, &JFJochDiffractionImage::setFeatureColor); connect(side_panel, &JFJochViewerSidePanel::setFeatureColor, calibrationWindow, &JFJochCalibrationWindow::setFeatureColor); connect(side_panel, &JFJochViewerSidePanel::setSpotColor, viewer, &JFJochDiffractionImage::setSpotColor); connect(side_panel, &JFJochViewerSidePanel::showHighestPixels, viewer, &JFJochDiffractionImage::showHighestPixels); connect(side_panel, &JFJochViewerSidePanel::showSaturatedPixels, viewer, &JFJochDiffractionImage::showSaturation); connect(viewer, &JFJochDiffractionImage::writeStatusBar, statusbar, &JFJochViewerStatusBar::display); connect(side_panel, &JFJochViewerSidePanel::writeStatusBar, statusbar, &JFJochViewerStatusBar::display); connect(metadataWindow, &JFJochViewerMetadataWindow::datasetUpdated, reading_worker, &JFJochImageReadingWorker::UpdateDataset); connect(reading_worker, &JFJochImageReadingWorker::setRings, side_panel, &JFJochViewerSidePanel::SetRings); connect(side_panel, &JFJochViewerSidePanel::resRingsSet, viewer, &JFJochDiffractionImage::setResolutionRing); connect(side_panel, &JFJochViewerSidePanel::ringModeSet, viewer, &JFJochDiffractionImage::setResolutionRingMode); connect(side_panel, &JFJochViewerSidePanel::highlightIceRings, viewer, &JFJochDiffractionImage::highlightIceRings); connect(calibrationWindow, &JFJochCalibrationWindow::loadCalibration, reading_worker, &JFJochImageReadingWorker::LoadCalibration); connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, calibrationWindow, &JFJochCalibrationWindow::datasetLoaded); connect(reading_worker, &JFJochImageReadingWorker::simpleImageLoaded, calibrationWindow, &JFJochCalibrationWindow::calibrationLoaded); connect(azintWindow, &JFJochAzIntWindow::settingsChanged, reading_worker, &JFJochImageReadingWorker::UpdateAzintSettings); connect(azintImageWindow, &JFJoch2DAzintImageWindow::zoomOnBin, viewer, &JFJochDiffractionImage::centerOnSpot); // Ensure worker is deleted in its own thread when the thread stops connect(reading_thread, &QThread::finished, reading_worker, &QObject::deleteLater); connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, this, [this](std::shared_ptr ds) { lastDataset = std::move(ds); }); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, this, [this](std::shared_ptr im) { lastImage = std::move(im); }); connect(menuBar, &JFJochViewerMenu::openDatasetInfo, this, &JFJochViewerWindow::NewDatasetInfo); NewDatasetInfo(); if (!file.isEmpty()) LoadFile(file, 0, 1); } JFJochViewerWindow::~JFJochViewerWindow() { if (reading_thread && reading_thread->isRunning()) { reading_thread->quit(); reading_thread->wait(); } } void JFJochViewerWindow::LoadFile(const QString &filename, qint64 image_number, qint64 summation) { emit LoadFileRequest(filename, image_number, summation); } void JFJochViewerWindow::LoadImage(qint64 image_number, qint64 summation) { emit LoadImageRequest(image_number, summation); } void JFJochViewerWindow::NewDatasetInfo() { auto info = new JFJochViewerDatasetInfo(this); info->datasetLoaded(lastDataset); info->imageLoaded(lastImage); auto dock = new QDockWidget(QString("Dataset info"), this); dock->setAllowedAreas(Qt::BottomDockWidgetArea); dock->setFeatures( QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable | QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetVerticalTitleBar); dock->setAttribute(Qt::WA_DeleteOnClose); dock->setWidget(info); addDockWidget(Qt::BottomDockWidgetArea, dock); // Wire signals like the initial dataset_info connect(reading_worker, &JFJochImageReadingWorker::datasetLoaded, info, &JFJochViewerDatasetInfo::datasetLoaded); connect(reading_worker, &JFJochImageReadingWorker::imageLoaded, info, &JFJochViewerDatasetInfo::imageLoaded); connect(info, &JFJochViewerDatasetInfo::imageSelected, reading_worker, &JFJochImageReadingWorker::LoadImage); connect(toolBarDisplay, &JFJochViewerToolbarDisplay::colorMapChanged, info, &JFJochViewerDatasetInfo::setColorMap); connect(info, &JFJochViewerDatasetInfo::writeStatusBar, statusbar, &JFJochViewerStatusBar::display); }