diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index f57d7eaa3..c0b76fab4 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -8,6 +8,9 @@ * The viewer plots spot count and background together on one plot, which is what a connection to a live source now shows by default. * The viewer's reprocessing panel is called Processing, and the jobs panel it shared that name with is called Jobs. * Expanding the viewer's powder-calibration section no longer widens the left-hand panel past the space it has, which used to push half of it out of sight. +* No section of the viewer's processing panel asks for more width than the panel has: geometry, unit cell, goniometer, spot finding and indexing all used to widen it when opened. +* The viewer states the angle of a rotation axis that does not turn as a single number, instead of adding a zero wedge to it. +* The viewer's image statistics show the sample-head chi and phi angles of a dataset that records them (an SLS Smargon), and nothing for one that does not. * Switching the viewer's plot between per-dataset and per-image no longer leaves the other mode's quantities in the selector, and each mode remembers what was last shown in it. * Re-initialising the broker after a DECTRIS run that never started no longer freezes it with no way to cancel. * Re-initialising the broker disconnects the previous run's stream reader, so a DECTRIS collection no longer starts and then stays empty because half its stream - the start message included - went to a reader nobody was listening to. diff --git a/viewer/widgets/JFJochViewerImageStatistics.cpp b/viewer/widgets/JFJochViewerImageStatistics.cpp index e254940f7..0b386dc66 100644 --- a/viewer/widgets/JFJochViewerImageStatistics.cpp +++ b/viewer/widgets/JFJochViewerImageStatistics.cpp @@ -123,6 +123,12 @@ JFJochViewerImageStatistics::JFJochViewerImageStatistics(QWidget *parent) : QWid rotation_angle = new QLabel(this); layout->addRow(rotation_angle_label, rotation_angle); + // Sample-head angles that do not move during a run (an SLS Smargon writes chi and phi). Both + // labels stay empty for a file that carries none, so the row costs nothing where it means nothing. + smargon_label = new QLabel(this); + smargon_angles = new QLabel(this); + layout->addRow(smargon_label, smargon_angles); + valid_values = new QLabel(this); layout->addRow(new QLabel("Valid values:"), valid_values); @@ -178,6 +184,8 @@ void JFJochViewerImageStatistics::loadImage(std::shared_ptrsetText(""); rotation_angle->setToolTip(""); rotation_angle_label->setText(""); + smargon_label->setText(""); + smargon_angles->setText(""); valid_values->setText(""); valid_values->setToolTip(""); spots->setText(""); @@ -235,10 +243,13 @@ void JFJochViewerImageStatistics::loadImage(std::shared_ptrsetToolTip(mkSampleTooltip(exp)); if (exp.GetGoniometer()) { + // An axis that is present but does not turn has no wedge to add: state the angle it stands at. + const float wedge = exp.GetGoniometer()->GetWedge_deg(); + const QString angle = TrimZeros(exp.GetGoniometer()->GetAngle_deg(image->ImageData().number), 3); rotation_angle_label->setText("Image angle:"); - rotation_angle->setText(QString("%1° + %2°") - .arg(TrimZeros(exp.GetGoniometer()->GetAngle_deg(image->ImageData().number), 3)) - .arg(TrimZeros(exp.GetGoniometer()->GetWedge_deg(), 3))); + rotation_angle->setText(wedge == 0.0f + ? QString("%1°").arg(angle) + : QString("%1° + %2°").arg(angle).arg(TrimZeros(wedge, 3))); rotation_angle->setToolTip(QString("Start angle: %1°
Increment: %2°") .arg(TrimZeros(exp.GetGoniometer()->GetStart_deg(), 3)) .arg(TrimZeros(exp.GetGoniometer()->GetIncrement_deg(), 3)) @@ -260,6 +271,16 @@ void JFJochViewerImageStatistics::loadImage(std::shared_ptrsetToolTip(""); } + if (const auto head = exp.GetDatasetSettings().GetSmargonPosition()) { + smargon_label->setText("Smargon:"); + smargon_angles->setText(QString("chi %1° / phi %2°") + .arg(TrimZeros(head->chi_deg, 3)) + .arg(TrimZeros(head->phi_deg, 3))); + } else { + smargon_label->setText(""); + smargon_angles->setText(""); + } + exposure_time->setText(QString("%1 s").arg(FormatTime(exp.GetImageTime()))); exposure_time->setToolTip(QString("Count time: %1 s
").arg(FormatTime(exp.GetImageCountTime()))); diff --git a/viewer/widgets/JFJochViewerImageStatistics.h b/viewer/widgets/JFJochViewerImageStatistics.h index bb7d721e6..090724023 100644 --- a/viewer/widgets/JFJochViewerImageStatistics.h +++ b/viewer/widgets/JFJochViewerImageStatistics.h @@ -21,6 +21,8 @@ class JFJochViewerImageStatistics : public QWidget { QLabel *exposure_time; QLabel *rotation_angle_label; QLabel *rotation_angle; + QLabel *smargon_label; + QLabel *smargon_angles; QLabel *spots; QLabel *valid_values; QLabel *indexed; diff --git a/viewer/widgets/JFJochViewerSettingsDock.cpp b/viewer/widgets/JFJochViewerSettingsDock.cpp index 8a7e52f02..2539599d6 100644 --- a/viewer/widgets/JFJochViewerSettingsDock.cpp +++ b/viewer/widgets/JFJochViewerSettingsDock.cpp @@ -142,6 +142,7 @@ JFJochViewerSettingsDock::JFJochViewerSettingsDock(const SpotFindingSettings &sp layout->addWidget(azintSection_); layout->addWidget(stack); layout->addStretch(); + } void JFJochViewerSettingsDock::setHttpConnection(bool connected, QString) { @@ -158,10 +159,13 @@ QWidget *JFJochViewerSettingsDock::BuildGeometrySection() { energy_ = new NumberLineEdit(1.0, 200.0, 12.4, 4, "keV", this); distance_ = new NumberLineEdit(10.0, 5000.0, 100.0, 2, "mm", this); - beamX_ = new NumberLineEdit(-20000.0, 20000.0, 0.0, 1, "px", this); - beamY_ = new NumberLineEdit(-20000.0, 20000.0, 0.0, 1, "px", this); - rot1_ = new NumberLineEdit(-180.0, 180.0, 0.0, 3, "°", this); - rot2_ = new NumberLineEdit(-180.0, 180.0, 0.0, 3, "°", this); + // Fields that share a row carry their unit in the row label instead of in a suffix: a spin box + // asks to be as wide as its longest possible value, and two or three of those abreast are wider + // than the dock. The panel already names units this way ("High resolution [Å]"). + beamX_ = new NumberLineEdit(-20000.0, 20000.0, 0.0, 1, "", this); + beamY_ = new NumberLineEdit(-20000.0, 20000.0, 0.0, 1, "", this); + rot1_ = new NumberLineEdit(-180.0, 180.0, 0.0, 3, "", this); + rot2_ = new NumberLineEdit(-180.0, 180.0, 0.0, 3, "", this); // Both are overwritten from the experiment as soon as a dataset is open; this is what they show // until then. polarizationOn_ = new QCheckBox("Polarization correction", this); @@ -197,9 +201,9 @@ QWidget *JFJochViewerSettingsDock::BuildGeometrySection() { geom->addRow("Photon energy", energy_); geom->addRow("Detector distance", distance_); - geom->addRow("Beam origin", beam); - geom->addRow("Detector tilt", tilt); - geom->addRow("", polarization); + geom->addRow("Beam origin [px]", beam); + geom->addRow("Detector tilt [°]", tilt); + geom->addRow(polarization); for (auto *f : {energy_, distance_, beamX_, beamY_, rot1_, rot2_, polarization_}) connect(f, &NumberLineEdit::newValue, this, [this] { EmitExperiment(); }); @@ -222,16 +226,22 @@ QWidget *JFJochViewerSettingsDock::BuildMXPage() { auto *cell = new QFormLayout(); cell->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); cellKnown_ = new QCheckBox("Known unit cell", page); - cell->addRow("", cellKnown_); - cellA_ = new NumberLineEdit(1.0, 2000.0, 79.0, 3, "Å", page); - cellB_ = new NumberLineEdit(1.0, 2000.0, 79.0, 3, "Å", page); - cellC_ = new NumberLineEdit(1.0, 2000.0, 38.0, 3, "Å", page); - cellAlpha_ = new NumberLineEdit(1.0, 179.0, 90.0, 2, "°", page); - cellBeta_ = new NumberLineEdit(1.0, 179.0, 90.0, 2, "°", page); - cellGamma_ = new NumberLineEdit(1.0, 179.0, 90.0, 2, "°", page); + cell->addRow(cellKnown_); + cellA_ = new NumberLineEdit(1.0, 2000.0, 79.0, 3, "", page); + cellB_ = new NumberLineEdit(1.0, 2000.0, 79.0, 3, "", page); + cellC_ = new NumberLineEdit(1.0, 2000.0, 38.0, 3, "", page); + cellAlpha_ = new NumberLineEdit(1.0, 179.0, 90.0, 2, "", page); + cellBeta_ = new NumberLineEdit(1.0, 179.0, 90.0, 2, "", page); + cellGamma_ = new NumberLineEdit(1.0, 179.0, 90.0, 2, "", page); spaceGroup_ = new NumberLineEdit(0.0, 230.0, 0.0, 0, "", page); spaceGroup_->setToolTip("Space group number (1–230); 0 = unset."); spaceGroupName_ = new QLabel("—", page); + // Three fields to a row, and a cell length can be four digits: let the row divide the width it + // has instead of each field demanding the width of its longest possible value, which is what + // made this the one section that still pushed the dock wider than it is. + for (auto *f : {cellA_, cellB_, cellC_, cellAlpha_, cellBeta_, cellGamma_}) + f->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed); + auto *abc = new QHBoxLayout(); abc->addWidget(cellA_); abc->addWidget(cellB_); abc->addWidget(cellC_); auto *angles = new QHBoxLayout(); @@ -240,8 +250,8 @@ QWidget *JFJochViewerSettingsDock::BuildMXPage() { auto *sgRow = new QHBoxLayout(); sgRow->addWidget(spaceGroup_, 1); sgRow->addWidget(spaceGroupName_, 1); - cell->addRow("a, b, c", abc); - cell->addRow("α, β, γ", angles); + cell->addRow("a, b, c [Å]", abc); + cell->addRow("α, β, γ [°]", angles); cell->addRow("Space group", sgRow); cellSection->setContentLayout(cell); layout->addWidget(cellSection); @@ -298,12 +308,12 @@ QWidget *JFJochViewerSettingsDock::BuildMXPage() { // the value rejected further down. auto *maxSpots = new NumberLineEdit(10.0f, static_cast(MAX_SPOT_COUNT), static_cast(max_spots_), 0, "", page); - spot->addRow("", adaptive); + spot->addRow(adaptive); spot->addRow("Signal/noise", snr); spot->addRow("Photon count", count); - spot->addRow("", autoHighResSpot); + spot->addRow(autoHighResSpot); spot->addRow("High resolution [Å]", highResSpot); - spot->addRow("", adaptiveMinPix); + spot->addRow(adaptiveMinPix); spot->addRow("Min pixels/spot", minPix); spot->addRow("Max spots/image", maxSpots); spotSection->setContentLayout(spot); @@ -355,6 +365,10 @@ QWidget *JFJochViewerSettingsDock::BuildMXPage() { auto *idx = new QFormLayout(); idx->setFieldGrowthPolicy(QFormLayout::AllNonFixedFieldsGrow); algo_ = new QComboBox(page); + // As in the calibrant combo: a combo is otherwise never narrower than its longest entry, which + // for these descriptions is wider than the dock. The current entry elides instead. + algo_->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); + algo_->setMinimumContentsLength(12); algo_->addItem("Auto", static_cast(IndexingAlgorithmEnum::Auto)); algo_->addItem("FFBIDX (GPU, known cell)", static_cast(IndexingAlgorithmEnum::FFBIDX)); algo_->addItem("FFT (GPU, de-novo)", static_cast(IndexingAlgorithmEnum::FFT)); @@ -365,6 +379,8 @@ QWidget *JFJochViewerSettingsDock::BuildMXPage() { algoDesc_->setWordWrap(true); algoDesc_->setStyleSheet("color: gray;"); auto *refine = new QComboBox(page); + refine->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLengthWithIcon); + refine->setMinimumContentsLength(12); refine->addItem("None", static_cast(GeomRefinementAlgorithmEnum::None)); refine->addItem("Orientation only", static_cast(GeomRefinementAlgorithmEnum::OrientationOnly)); refine->addItem("Beam center + lattice", static_cast(GeomRefinementAlgorithmEnum::BeamCenter)); @@ -374,7 +390,7 @@ QWidget *JFJochViewerSettingsDock::BuildMXPage() { refine->addItem("Flex (best per-image refinement)", static_cast(GeomRefinementAlgorithmEnum::Flex)); refine->setCurrentIndex(refine->findData(static_cast(indexing_.GetGeomRefinementAlgorithm()))); idx->addRow("Algorithm", algo_); - idx->addRow("", algoDesc_); + idx->addRow(algoDesc_); idx->addRow("Refinement", refine); idxSection->setContentLayout(idx); layout->addWidget(idxSection); @@ -442,8 +458,8 @@ QWidget *JFJochViewerSettingsDock::BuildGoniometerSection() { gridNFast_ = new NumberLineEdit(1.0, 100000.0, DEFAULT_GRID_N_FAST, 0, "", this); gridNFast_->setToolTip("Points along the fast axis. The number of slow rows follows from the " "number of images."); - gridStepX_ = new NumberLineEdit(-10000.0, 10000.0, DEFAULT_GRID_STEP_UM, 1, "μm", this); - gridStepY_ = new NumberLineEdit(-10000.0, 10000.0, DEFAULT_GRID_STEP_UM, 1, "μm", this); + gridStepX_ = new NumberLineEdit(-10000.0, 10000.0, DEFAULT_GRID_STEP_UM, 1, "", this); + gridStepY_ = new NumberLineEdit(-10000.0, 10000.0, DEFAULT_GRID_STEP_UM, 1, "", this); const QString stepTip = "Distance between neighbouring points, in x and y. Negative = the scan " "runs towards decreasing x / y."; gridStepX_->setToolTip(stepTip); @@ -464,17 +480,17 @@ QWidget *JFJochViewerSettingsDock::BuildGoniometerSection() { auto *gridFlags = new QHBoxLayout(); gridFlags->addWidget(gridVertical_); gridFlags->addWidget(gridSnake_); - form->addRow("", modeStill_); - form->addRow("", modeRotation_); + form->addRow(modeStill_); + form->addRow(modeRotation_); form->addRow("Axis name", axisName_); form->addRow("Axis vector", axis); form->addRow("Start angle", rotStart_); form->addRow("Increment", rotIncrement_); - form->addRow("", modeGrid_); + form->addRow(modeGrid_); form->addRow("Points (fast)", gridNFast_); - form->addRow("Step x, y", step); - form->addRow("", gridFlags); - form->addRow("", gridSummary_); + form->addRow("Step x, y [μm]", step); + form->addRow(gridFlags); + form->addRow(gridSummary_); section->setContentLayout(form); EnableRotationFields(false); // datasetLoaded picks the mode the file describes @@ -621,7 +637,7 @@ QWidget *JFJochViewerSettingsDock::BuildAzIntSection() { azimBins->addItem(QString::number(b), b); azimBins->setCurrentIndex(azimBins->findData(azint_.GetAzimuthalBinCount())); az->addRow("Low Q [Å⁻¹]", lowQ); - az->addRow("", autoHighQ); + az->addRow(autoHighQ); az->addRow("High Q [Å⁻¹]", highQ); az->addRow("Q spacing [Å⁻¹]", spacing); az->addRow("Azimuthal bins", azimBins); @@ -737,9 +753,9 @@ QWidget *JFJochViewerSettingsDock::BuildBraggSection() { auto *gaussian = new QCheckBox("Gaussian profile fit", this); gaussian->setChecked(bragg_.GetIntegrator() != IntegratorMode::BoxSum); gaussian->setToolTip("Profile-fit the spots (more accurate intensities); off = classical box-sum."); - auto *r1 = new NumberLineEdit(1.0f, 30.0f, bragg_.GetR1(), 1, "px", this); - auto *r2 = new NumberLineEdit(1.0f, 30.0f, bragg_.GetR2(), 1, "px", this); - auto *r3 = new NumberLineEdit(1.0f, 30.0f, bragg_.GetR3(), 1, "px", this); + auto *r1 = new NumberLineEdit(1.0f, 30.0f, bragg_.GetR1(), 1, "", this); + auto *r2 = new NumberLineEdit(1.0f, 30.0f, bragg_.GetR2(), 1, "", this); + auto *r3 = new NumberLineEdit(1.0f, 30.0f, bragg_.GetR3(), 1, "", this); auto *radii = new QHBoxLayout(); radii->addWidget(r1); radii->addWidget(r2); radii->addWidget(r3); // Background trim: use the old symmetric trimmed mean for the r2..r3 ring (drop the lowest and @@ -757,9 +773,9 @@ QWidget *JFJochViewerSettingsDock::BuildBraggSection() { auto *trimRow = new QHBoxLayout(); trimRow->addWidget(bkgTrim); trimRow->addWidget(bkgTrimFrac, 1); - form->addRow("", gaussian); - form->addRow("Radii r1/r2/r3", radii); - form->addRow("", trimRow); + form->addRow(gaussian); + form->addRow("Radii r1/r2/r3 [px]", radii); + form->addRow(trimRow); section->setContentLayout(form); auto emitBragg = [=, this] { @@ -814,19 +830,19 @@ QWidget *JFJochViewerSettingsDock::BuildScalingSection() { auto *lowRes = new NumberLineEdit(5.0f, 500.0f, scaling_.GetLowResolutionLimit_A().value_or(50.0), 1, "Å", this); lowRes->setEnabled(limitLowRes->isChecked()); - form->addRow("", friedel); - form->addRow("", corrections); - form->addRow("", partRefine); + form->addRow(friedel); + form->addRow(corrections); + form->addRow(partRefine); // Compact, and aligned with the checkboxes above: the limit checkbox + value sit together in the // field column (not as a row label, which would indent it differently). auto *resRow = new QHBoxLayout(); resRow->addWidget(limitRes); resRow->addWidget(highRes, 1); - form->addRow("", resRow); + form->addRow(resRow); auto *lowResRow = new QHBoxLayout(); lowResRow->addWidget(limitLowRes); lowResRow->addWidget(lowRes, 1); - form->addRow("", lowResRow); + form->addRow(lowResRow); section->setContentLayout(form); auto emitScaling = [=, this] {