Merge branch 'viewer-bkg-slider' into rc173 (viewer: background slider on demand, Auto zeroes the background, no black plot line)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,9 @@
|
||||
* jfjoch_viewer's reference dataset accepts a structure-factor mmCIF as well as an MTZ, and a processing job can name an atomic model to validate the merged data against, as `rugnux --model` does.
|
||||
* jfjoch_viewer keeps a separate preferred dataset-info plot for grid scans, where "Spots + background" means the spot count.
|
||||
* jfjoch_viewer's dark theme no longer leaves navy buttons, red warnings and chart guide lines at their light-theme colours.
|
||||
* jfjoch_viewer hides the background slider unless it is switched on in the View menu or the background is raised with `B` + wheel, and remembers the choice.
|
||||
* jfjoch_viewer's Auto contrast, continuous or one-shot, sets the background back to zero.
|
||||
* jfjoch_viewer draws a dataset-info plot without a run colour, such as a live broker dataset, in blue on the light theme and orange on the dark theme instead of black.
|
||||
* `rugnux --model` draws its null's random placements away from every orientation equivalent to the model's under the space group or a twin law, so a random placement can no longer be refined onto the model's own solution and make the crystal's own model read as not fitting.
|
||||
* Rugnux adds beam-stop holder arms that let part of the beam through to the beam-stop mask, without changing the mask of a sweep that has none.
|
||||
* Rugnux's `--model` rigid-body refinement computes the model's density and solvent mask on all threads, with results unchanged.
|
||||
|
||||
@@ -98,8 +98,9 @@ open button do the same, and **File ▸ Open HTTP** connects to a running `jfjoc
|
||||

|
||||
|
||||
The top toolbars step through the images (slider, first/previous/next/last, `Jump` and `Sum` for
|
||||
summing consecutive frames) and set the display (foreground and background limits, `Auto`
|
||||
contrast, HDR, colour map, font size, theme). The image in the middle zooms with the wheel and
|
||||
summing consecutive frames) and set the display (foreground limit, `Auto` contrast, HDR, colour
|
||||
map, font size, theme). The background limit has a slider of its own, shown from View >
|
||||
Background slider or as soon as `B` + wheel raises it; `Auto` sets it back to zero. The image in the middle zooms with the wheel and
|
||||
pans by dragging; hovering shows the pixel position, its value and the resolution on the status
|
||||
bar. The **Inspector** on the right lists the dataset's metadata and, once an image has been
|
||||
analysed, its spot count, background, indexing result and resolution estimate; the **Magnifier**
|
||||
@@ -187,7 +188,7 @@ keyboard without them `Home` / `End` are `Fn`+`←` / `Fn`+`→` and `Page Up` /
|
||||
| `Ctrl` + wheel | Move the foreground in multiplicative steps (×1.15 per notch) |
|
||||
| `F` held + wheel | Same as `Shift` + wheel, for as long as `F` is held |
|
||||
| `B` held + wheel | Move the background (lower contrast limit) in linear steps, for as long as `B` is held |
|
||||
| `A` | Apply auto-contrast once; press it again to switch on continuous Auto |
|
||||
| `A` | Apply auto-contrast once (background back to zero); press it again to switch on continuous Auto |
|
||||
| `Home` / `End` | Jump to the first / last image in the dataset |
|
||||
| `Page Up` / `Page Down` | Step one image forward / back |
|
||||
| Hover | Status bar shows the pixel position, its value and the resolution |
|
||||
|
||||
@@ -74,7 +74,7 @@ JFJochViewerMenu::JFJochViewerMenu(QWidget *parent) : QMenuBar(parent) {
|
||||
const QAction *dockCalibration = dockMenu->addAction("New dataset info plot");
|
||||
connect(dockCalibration, &QAction::triggered, [this] { emit openDatasetInfo();});
|
||||
|
||||
QMenu *viewMenu = addMenu("View");
|
||||
viewMenu = addMenu("View");
|
||||
const QAction *imageLayout = viewMenu->addAction("Image layout");
|
||||
connect(imageLayout, &QAction::triggered, this, &JFJochViewerMenu::imageLayoutSelected);
|
||||
const QAction *processingLayout = viewMenu->addAction("Processing layout");
|
||||
@@ -91,7 +91,7 @@ JFJochViewerMenu::JFJochViewerMenu(QWidget *parent) : QMenuBar(parent) {
|
||||
remoteMode->setChecked(RemoteDisplayMode());
|
||||
connect(remoteMode, &QAction::toggled, this, [](bool on) { SetRemoteDisplayMode(on); });
|
||||
|
||||
viewMenu->addSeparator();
|
||||
viewTogglesAnchor = viewMenu->addSeparator();
|
||||
QMenu *themeMenu = viewMenu->addMenu("Theme");
|
||||
auto *themeGroup = new QActionGroup(this);
|
||||
const ThemeChoice currentTheme = LoadThemeChoice();
|
||||
@@ -180,6 +180,10 @@ void JFJochViewerMenu::AddWindowEntry(JFJochHelperWindow *window, const QString
|
||||
connect(window, &JFJochHelperWindow::closing, [action] {action->setChecked(false);});
|
||||
}
|
||||
|
||||
void JFJochViewerMenu::AddViewToggle(QAction *action) {
|
||||
viewMenu->insertAction(viewTogglesAnchor, action);
|
||||
}
|
||||
|
||||
void JFJochViewerMenu::AddDockEntry(QDockWidget *dock, const QString &name) {
|
||||
auto *action = dock->toggleViewAction(); // checkable, stays in sync with the dock visibility
|
||||
action->setText(name);
|
||||
|
||||
@@ -24,6 +24,8 @@ class JFJochViewerMenu : public QMenuBar {
|
||||
QAction *toggleCalibrationWindowAction = nullptr;
|
||||
|
||||
QMenu *windowMenu = nullptr;
|
||||
QMenu *viewMenu = nullptr;
|
||||
QAction *viewTogglesAnchor = nullptr; // View-menu toggles owned elsewhere go before this
|
||||
QActionGroup *fontZoomGroup = nullptr;
|
||||
QFont baseFont; // the font the desktop handed us; the zoom is a multiple of it
|
||||
int fontZoom = 100; // per cent: 100, 125 or 150
|
||||
@@ -37,6 +39,8 @@ public:
|
||||
void AddWindowEntry(JFJochHelperWindow *window, const QString &name);
|
||||
// Adds a dock's show/hide toggle to the Window menu (for docked panels).
|
||||
void AddDockEntry(QDockWidget *dock, const QString &name);
|
||||
// Adds a checkable action owned by another widget (e.g. a toolbar) to the View menu.
|
||||
void AddViewToggle(QAction *action);
|
||||
// Back to 100 %, for "Reset all settings to defaults".
|
||||
void ResetFontZoom();
|
||||
// 100, 125 or 150 per cent; also reachable from the display toolbar's size buttons.
|
||||
|
||||
@@ -680,6 +680,9 @@ JFJochViewerWindow::JFJochViewerWindow(QWidget *parent, bool dbus, const QString
|
||||
viewer->setHDRMode(hdrMode);
|
||||
toolBarDisplay->updateHDRMode(hdrMode);
|
||||
|
||||
menuBar->AddViewToggle(toolBarDisplay->backgroundSliderAction());
|
||||
toolBarDisplay->showBackgroundSlider(settings.value("backgroundSlider", false).toBool());
|
||||
|
||||
if (!file.isEmpty())
|
||||
LoadFile(file, 0, 1, false);
|
||||
}
|
||||
@@ -731,6 +734,7 @@ void JFJochViewerWindow::ResetAllSettings() {
|
||||
viewer->setAutoForeground(false); // emits autoForegroundChanged -> toolbar button state
|
||||
viewer->setHDRMode(false);
|
||||
toolBarDisplay->updateHDRMode(false);
|
||||
toolBarDisplay->showBackgroundSlider(false);
|
||||
|
||||
for (auto *info : findChildren<JFJochViewerDatasetInfo *>())
|
||||
info->resetPlotDefaults();
|
||||
@@ -800,6 +804,7 @@ void JFJochViewerWindow::closeEvent(QCloseEvent *event) {
|
||||
settings.setValue("colorMap", toolBarDisplay->colorMap());
|
||||
settings.setValue("autoForeground", toolBarDisplay->autoForeground());
|
||||
settings.setValue("hdrMode", toolBarDisplay->hdrMode());
|
||||
settings.setValue("backgroundSlider", toolBarDisplay->backgroundSliderShown());
|
||||
QMainWindow::closeEvent(event);
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,10 @@ namespace {
|
||||
pen.setWidthF(font_height / 5.0);
|
||||
line->setPen(pen);
|
||||
}
|
||||
|
||||
QColor DefaultLineColor() {
|
||||
return DarkTheme() ? QColor(0xff, 0x7f, 0x0e) : QColor(0x1f, 0x77, 0xb4);
|
||||
}
|
||||
}
|
||||
|
||||
JFJochDatasetInfoChartView::JFJochDatasetInfoChartView(QWidget *parent)
|
||||
@@ -403,8 +407,9 @@ void JFJochDatasetInfoChartView::buildTimeDomainChart() {
|
||||
series = new QLineSeries(this);
|
||||
if (!primaryName_.isEmpty())
|
||||
series->setName(primaryName_);
|
||||
if (primary_color_.isValid())
|
||||
series->setColor(primary_color_);
|
||||
// Without a run colour (a live HTTP dataset has no run list) the line would keep the
|
||||
// default black pen; it takes the spot-count blue on light, the background orange on dark.
|
||||
series->setColor(primary_color_.isValid() ? primary_color_ : DefaultLineColor());
|
||||
setSeriesPenWidth(series, fontMetrics().height());
|
||||
currentSeries = new QScatterSeries(this);
|
||||
currentSeries->setColor(palette().color(QPalette::WindowText)); // "current image" marker: not a run colour
|
||||
|
||||
@@ -983,9 +983,19 @@ void JFJochDiffractionImage::loadImage(std::shared_ptr<const JFJochReaderImage>
|
||||
}
|
||||
}
|
||||
|
||||
// Auto contrast sets the whole display range, so it takes the black point back to zero.
|
||||
void JFJochDiffractionImage::ResetBackground() {
|
||||
if (background == 0.0f)
|
||||
return;
|
||||
background = 0.0f;
|
||||
emit backgroundChanged(background);
|
||||
}
|
||||
|
||||
void JFJochDiffractionImage::setAutoForeground(bool input) {
|
||||
auto_fg = input;
|
||||
one_shot_auto_ = false; // whatever `A` did before, the next press starts as a one-shot again
|
||||
if (auto_fg)
|
||||
ResetBackground();
|
||||
// If auto_foreground is not set, then view stays with the current settings till these are explicitly changed
|
||||
UpdateForeground();
|
||||
RenderImage();
|
||||
@@ -1007,6 +1017,7 @@ void JFJochDiffractionImage::oneShotAutoForeground() {
|
||||
return;
|
||||
// Unlike a manual foreground change this leaves auto_fg alone (it is off here either way).
|
||||
foreground = *val;
|
||||
ResetBackground();
|
||||
one_shot_auto_ = true;
|
||||
ScheduleRenderImage();
|
||||
emit foregroundChanged(foreground);
|
||||
|
||||
@@ -103,6 +103,7 @@ private:
|
||||
// The foreground the current image suggests: the top of the valid range in HDR mode, the
|
||||
// auto-contrast value otherwise. Empty when there is no image to take it from.
|
||||
[[nodiscard]] std::optional<float> AutoForegroundValue() const;
|
||||
void ResetBackground();
|
||||
bool one_shot_auto_ = false; // `A` applied the auto value; pressing it again makes Auto permanent
|
||||
void leaveEvent(QEvent *event) override;
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ JFJochViewerToolbarDisplay::JFJochViewerToolbarDisplay(QWidget *parent)
|
||||
foreground_slider->setMaximumWidth(slider_cap);
|
||||
addWidget(foreground_slider);
|
||||
|
||||
addWidget(new QLabel(" Background ", this));
|
||||
background_label_action = addWidget(new QLabel(" Background ", this));
|
||||
|
||||
background_slider = new SliderPlusBox(0, MAX_SLIDER_NO_IMAGE, 1.0, 1, this,
|
||||
SliderPlusBox::ScaleType::Logarithmic);
|
||||
@@ -47,7 +47,12 @@ JFJochViewerToolbarDisplay::JFJochViewerToolbarDisplay(QWidget *parent)
|
||||
" the mouse wheel");
|
||||
SetThemedStyleSheet(background_slider, SliderStyle);
|
||||
background_slider->setMaximumWidth(slider_cap);
|
||||
addWidget(background_slider);
|
||||
background_slider_action = addWidget(background_slider);
|
||||
|
||||
show_background_action = new QAction("Background slider", this);
|
||||
show_background_action->setCheckable(true);
|
||||
connect(show_background_action, &QAction::toggled, this, &JFJochViewerToolbarDisplay::showBackgroundSlider);
|
||||
showBackgroundSlider(false);
|
||||
|
||||
auto makeToggle = [this](const QString &text, const QString &tip) {
|
||||
auto *b = new QToolButton(this);
|
||||
@@ -137,6 +142,8 @@ void JFJochViewerToolbarDisplay::backgroundSet(double val) {
|
||||
}
|
||||
|
||||
void JFJochViewerToolbarDisplay::updateBackground(float val) {
|
||||
if (val > 0.0f)
|
||||
showBackgroundSlider(true);
|
||||
pending_background_ = val;
|
||||
if (RemoteDisplayMode() && background_rate_.isValid()
|
||||
&& background_rate_.elapsed() < kRemoteRepaintIntervalMs) {
|
||||
@@ -147,6 +154,12 @@ void JFJochViewerToolbarDisplay::updateBackground(float val) {
|
||||
ApplyPendingBackground();
|
||||
}
|
||||
|
||||
void JFJochViewerToolbarDisplay::showBackgroundSlider(bool val) {
|
||||
show_background_action->setChecked(val);
|
||||
background_label_action->setVisible(val);
|
||||
background_slider_action->setVisible(val);
|
||||
}
|
||||
|
||||
void JFJochViewerToolbarDisplay::ApplyPendingBackground() {
|
||||
background_rate_.restart();
|
||||
QSignalBlocker blocker(background_slider);
|
||||
|
||||
@@ -22,6 +22,11 @@ class JFJochViewerToolbarDisplay : public QToolBar {
|
||||
|
||||
SliderPlusBox *foreground_slider;
|
||||
SliderPlusBox *background_slider;
|
||||
// The background slider is rarely needed, so it is hidden unless this toggle (View menu) is on.
|
||||
// A non-zero black point switches it on, so an active background is never invisible.
|
||||
QAction *background_label_action;
|
||||
QAction *background_slider_action;
|
||||
QAction *show_background_action;
|
||||
QToolButton *auto_foreground_button;
|
||||
QToolButton *hdr_mode_button;
|
||||
QComboBox *color_map_select;
|
||||
@@ -48,6 +53,8 @@ public:
|
||||
[[nodiscard]] int colorMap() const { return color_map_select->currentIndex(); }
|
||||
[[nodiscard]] bool autoForeground() const { return auto_foreground_button->isChecked(); }
|
||||
[[nodiscard]] bool hdrMode() const { return hdr_mode_button->isChecked(); }
|
||||
[[nodiscard]] bool backgroundSliderShown() const { return show_background_action->isChecked(); }
|
||||
[[nodiscard]] QAction *backgroundSliderAction() const { return show_background_action; }
|
||||
|
||||
signals:
|
||||
void setForeground(float val);
|
||||
@@ -63,6 +70,7 @@ public slots:
|
||||
void updateAutoForeground(bool val);
|
||||
void updateColorMap(int val);
|
||||
void updateHDRMode(bool val);
|
||||
void showBackgroundSlider(bool val);
|
||||
void updateFontZoom(int percent);
|
||||
void imageLoaded(std::shared_ptr<const JFJochReaderImage> image);
|
||||
private slots:
|
||||
|
||||
@@ -30,8 +30,8 @@ namespace {
|
||||
{"Shift + wheel", "Move the foreground (upper contrast limit) in linear steps"},
|
||||
{ctrl + " + wheel", "Move the foreground in multiplicative steps (×1.15 per notch)"},
|
||||
{"F held + wheel", "Same as Shift + wheel, for as long as F is held"},
|
||||
{"B held + wheel", "Move the background (lower contrast limit) in linear steps, for as long as B is held"},
|
||||
{"A", "Apply auto-contrast once; press again to switch on continuous Auto"},
|
||||
{"B held + wheel", "Move the background (lower contrast limit) in linear steps, for as long as B is held; shows the background slider"},
|
||||
{"A", "Apply auto-contrast once (background back to zero); press again to switch on continuous Auto"},
|
||||
{home_end, "Jump to the first / last image in the dataset"},
|
||||
{page_up_down, "Step one image forward / back"},
|
||||
{"Hover", "Status bar shows the pixel position, its value and the resolution"},
|
||||
|
||||
Reference in New Issue
Block a user