// SPDX-FileCopyrightText: 2025 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #include "JFJochViewerToolbar.h" #include "../common/ColorScale.h" #include #include #include #include #include #include #include #include "widgets/NumericComboBox.h" JFJochViewerToolbar::JFJochViewerToolbar(QWidget *parent) : QToolBar(parent) { image_count_in_dataset = 0; auto title = new QLabel("Image number ", this); addWidget(title); leftmost_button = new QPushButton("|⇐", this); leftmost_button->setFixedWidth(32); addWidget(leftmost_button); left_button = new QPushButton("⇐", this); left_button->setFixedWidth(32); addWidget(left_button); current_image_edit_validator = new QIntValidator(0, 1000, this); current_image_edit = new QLineEdit("0", this); current_image_edit->setFixedWidth(50); current_image_edit->setAlignment(Qt::AlignmentFlag::AlignRight); current_image_edit->setValidator(current_image_edit_validator); addWidget(current_image_edit); total_number_label = new QLabel("/0", this); addWidget(total_number_label); right_button = new QPushButton("⇒", this); right_button->setFixedWidth(32); addWidget(right_button); rightmost_button = new QPushButton("⇒|", this); rightmost_button->setFixedWidth(32); addWidget(rightmost_button); addWidget(new QLabel(" Jump:", this)); jump = new NumericComboBox({1, 2, 5, 10, 20, 100, 500}, 1, 999, this); connect(jump, &NumericComboBox::valueChanged, this, &JFJochViewerToolbar::setImageJump); addWidget(jump); addWidget(new QLabel(" Sum:", this)); auto sum = new NumericComboBox({1, 2, 5, 10, 20, 50, 100}, 1, 10000, this); connect(sum, &NumericComboBox::valueChanged, this, &JFJochViewerToolbar::setSummation); addWidget(sum); image_number_slider = new QSlider(Qt::Horizontal, this); addWidget(image_number_slider); image_number_slider_timer = new QTimer(this); image_number_slider_timer->setSingleShot(true); addWidget(new QLabel(" Movie:", this)); movie_button = new QPushButton("▶"); movie_button->setCheckable(true); movie_button->setFixedWidth(32); addWidget(movie_button); movie_timer = new QTimer(this); movie_timer->setInterval(movie_interval); addWidget(new QLabel(" Online sync:", this)); autoload_button = new QPushButton("🔄"); autoload_button->setCheckable(true); autoload_button->setFixedWidth(32); addWidget(autoload_button); connect(movie_button, &QPushButton::clicked, this, &JFJochViewerToolbar::movieButtonPressed); connect(autoload_button, &QPushButton::clicked, this, &JFJochViewerToolbar::autoloadButtonPressed); connect(movie_timer, &QTimer::timeout, this, &JFJochViewerToolbar::movieTimerTimeout); auto *stretch = new QWidget(this); stretch->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); addWidget(stretch); addSeparator(); auto title_fg = new QLabel("Foreground ", this); addWidget(title_fg); foreground_slider = new SliderPlusBox(1, 30000, 1.0, 1, this, SliderPlusBox::ScaleType::Logarithmic); foreground_slider->setValue(10); addWidget(foreground_slider); // Initialize QComboBox with the options color_map_select = new QComboBox(this); color_map_select->addItem("Viridis", static_cast(ColorScaleEnum::Viridis)); color_map_select->addItem("Heat", static_cast(ColorScaleEnum::Heat)); color_map_select->addItem("Indigo", static_cast(ColorScaleEnum::Indigo)); color_map_select->addItem("B/W", static_cast(ColorScaleEnum::BW)); color_map_select->setCurrentIndex(static_cast(ColorScaleEnum::Indigo)); addWidget(color_map_select); auto *stretch_2 = new QWidget(this); stretch_2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); addWidget(stretch_2); setImageNumber(0, 0); connect(left_button, &QPushButton::clicked, this, &JFJochViewerToolbar::leftButtonPressed); connect(right_button, &QPushButton::clicked, this, &JFJochViewerToolbar::rightButtonPressed); connect(leftmost_button, &QPushButton::clicked, this, &JFJochViewerToolbar::leftmostButtonPressed); connect(rightmost_button, &QPushButton::clicked, this, &JFJochViewerToolbar::rightmostButtonPressed); connect(current_image_edit, &QLineEdit::editingFinished, this, &JFJochViewerToolbar::editFinalized); connect(image_number_slider, &QSlider::sliderPressed, this, &JFJochViewerToolbar::imageNumberSliderPressed); connect(image_number_slider, &QSlider::sliderReleased, this, &JFJochViewerToolbar::imageNumberSliderReleased); connect(image_number_slider, &QSlider::sliderMoved, this, &JFJochViewerToolbar::imageNumberSliderMoved); connect(foreground_slider, &SliderPlusBox::valueChanged, this, &JFJochViewerToolbar::foregroundSet); connect(color_map_select, QOverload::of(&QComboBox::currentIndexChanged), this, &JFJochViewerToolbar::colorComboBoxSet); } void JFJochViewerToolbar::updateButtons() { if (image_count_in_dataset > 0) { current_image_edit->setDisabled(false); current_image_edit->setText(QString::number(curr_image)); current_image_edit_validator->setRange(0, image_count_in_dataset - 1); left_button->setDisabled(curr_image < jump_value); right_button->setDisabled(curr_image >= image_count_in_dataset - jump_value); leftmost_button->setDisabled(curr_image == 0); rightmost_button->setDisabled(curr_image == image_count_in_dataset - 1); image_number_slider->setRange(0, image_count_in_dataset - 1); image_number_slider->setEnabled(true); if (!image_number_slider_manual) image_number_slider->setValue(curr_image); } else { left_button->setDisabled(true); right_button->setDisabled(true); leftmost_button->setDisabled(true); rightmost_button->setDisabled(true); current_image_edit->setText(QString::number(0)); image_number_slider->setValue(0); image_number_slider->setDisabled(true); } if (image_count_in_dataset == 0) total_number_label->setText("/ - "); else total_number_label->setText("/" + QString::number(image_count_in_dataset - 1)); } void JFJochViewerToolbar::setImageNumber(int64_t total_images, int64_t current_image) { if (image_count_in_dataset != total_images && mode == ToolbarMode::Movie) { mode = ToolbarMode::None; updateAutoload(); } image_count_in_dataset = total_images; curr_image = current_image; updateButtons(); } void JFJochViewerToolbar::leftButtonPressed() { if (curr_image >= jump_value) { emit loadImage(curr_image - jump_value, sum); mode = ToolbarMode::None; updateAutoload(); } } void JFJochViewerToolbar::rightButtonPressed() { if (curr_image < image_count_in_dataset - jump_value) { emit loadImage(curr_image + jump_value, sum); mode = ToolbarMode::None; updateAutoload(); } } void JFJochViewerToolbar::rightmostButtonPressed() { emit loadImage(image_count_in_dataset - 1, sum); mode = ToolbarMode::None; updateAutoload(); } void JFJochViewerToolbar::leftmostButtonPressed() { emit loadImage(0, sum); mode = ToolbarMode::None; updateAutoload(); } void JFJochViewerToolbar::imageNumberSliderPressed() { image_number_slider_manual = true; mode = ToolbarMode::None; updateAutoload(); } void JFJochViewerToolbar::imageNumberSliderReleased() { image_number_slider_manual = false; int val = image_number_slider->value(); emit loadImage(val, sum); } void JFJochViewerToolbar::imageNumberSliderMoved(int val) { if (!image_number_slider_timer->isActive()) { emit loadImage(val, sum); image_number_slider_timer->start(300); } } void JFJochViewerToolbar::editFinalized() { bool ok; int editedValue = current_image_edit->text().toInt(&ok); if (ok && editedValue >= 0 && editedValue <= image_count_in_dataset - 1) { emit loadImage(editedValue, sum); mode = ToolbarMode::None; updateAutoload(); } } void JFJochViewerToolbar::foregroundSet(double val) { emit setForeground(static_cast(val)); } void JFJochViewerToolbar::updateForeground(float val) { foreground_slider->setValue(val); } void JFJochViewerToolbar::colorComboBoxSet(int val) { emit colorMapChanged(val); } void JFJochViewerToolbar::setImageJump(int val) { jump_value = val; updateButtons(); mode = ToolbarMode::None; updateAutoload(); } void JFJochViewerToolbar::setSummation(int val) { sum = val; jump_value = val; jump->setValue(val); updateButtons(); emit loadImage(curr_image, sum); mode = ToolbarMode::None; updateAutoload(); } void JFJochViewerToolbar::autoloadButtonPressed() { if (mode == ToolbarMode::Autoload) mode = ToolbarMode::None; else mode = ToolbarMode::Autoload; updateAutoload(); } void JFJochViewerToolbar::movieButtonPressed() { if (mode == ToolbarMode::Movie) mode = ToolbarMode::None; else mode = ToolbarMode::Movie; updateAutoload(); } void JFJochViewerToolbar::movieTimerTimeout() { switch (mode) { case ToolbarMode::Autoload: emit loadImage(-1, 1); break; case ToolbarMode::Movie: if (curr_image < image_count_in_dataset - jump_value) emit loadImage(curr_image + jump_value, sum); else emit loadImage(0, sum); break; case ToolbarMode::None: // Do nothing break; } } void JFJochViewerToolbar::updateAutoload() { switch (mode) { case ToolbarMode::None: autoload_button->setChecked(false); movie_button->setChecked(false); movie_timer->stop(); break; case ToolbarMode::Autoload: autoload_button->setChecked(true); movie_button->setChecked(false); movie_timer->start(); break; case ToolbarMode::Movie: if (image_count_in_dataset > 0) { autoload_button->setChecked(false); movie_button->setChecked(true); movie_timer->start(); } else { autoload_button->setChecked(false); movie_button->setChecked(false); movie_timer->stop(); mode = ToolbarMode::None; } break; } } void JFJochViewerToolbar::setAutoloadMode(JFJochViewerToolbar::ToolbarMode input) { mode = input; updateAutoload(); }