GitHub Viewer
#include "ImageViewer.h"
#include "ui_ImageViewer.h"
#include
#include
#include
#include
#include
#include
#include
ImageViewer::ImageViewer(QWidget* parent) :
QWidget(parent),
ui(new Ui::ImageViewer),
m_image_size(0, 0),
m_pan_mode{false}
{
ui->setupUi(this);
ui->scrollArea->viewport()->installEventFilter(this);
connect(ui->buttonOriginalSize, &QToolButton::clicked, this, [this]{ scaleImage(100); });
ui->labelView->addAction(ui->actionPrintImage);
}
ImageViewer::~ImageViewer()
{
delete ui;
}
void ImageViewer::resetImage()
{
ui->labelView->setPixmap(QPixmap(0, 0));
}
void ImageViewer::setImage(const QImage& image)
{
auto widget_size = ui->scrollArea->viewport()->size();
m_image_size = image.size();
ui->labelView->setMaximumSize(m_image_size.scaled(widget_size, Qt::KeepAspectRatio));
ui->labelView->setPixmap(QPixmap::fromImage(image));
// If the image is larger than the viewport scale it to fit the viewport.
// If the image is smaller than the viewport show it in its original size.
if(!isQSizeCovered(m_image_size))
ui->buttonFitToWindow->setChecked(true);
else
scaleImage(100);
}
bool ImageViewer::isQSizeCovered(QSize rect)
{
auto widget_size = ui->scrollArea->viewport()->size();
return widget_size.width() >= rect.width() && widget_size.height() >= rect.height();
}
bool ImageViewer::eventFilter(QObject* /*obj*/, QEvent* e) {
auto e_type = e->type();
if (e_type == QEvent::Wheel) {
auto *wheel_event = static_cast(e);
auto step = ui->sliderScale->pageStep();
if (wheel_event->angleDelta().y() < 0) {
step = -step;
}
scaleImage(ui->sliderScale->value() + step);
e->accept();
return true;
}
if (ui->buttonFitToWindow->isChecked()) {
if (e_type == QEvent::Resize)
scaleToFitWindow(true);
} else if (e_type >= QEvent::MouseButtonPress && e_type button() == Qt::LeftButton &&
!isQSizeCovered(ui->labelView->size())) {
m_mouse_down = mouse_event->globalPos();
m_pan_mode = true;
ui->scrollArea->setCursor(Qt::ClosedHandCursor);
} else if (e_type == QEvent::MouseMove && m_pan_mode) {
auto dx = mouse_event->globalX() - m_mouse_down.x();
auto dy = mouse_event->globalY() - m_mouse_down.y();
m_mouse_down = mouse_event->globalPos();
if (dx != 0) {
ui->scrollArea->horizontalScrollBar()->setValue(ui->scrollArea->horizontalScrollBar()->value() - dx);
}
if (dy != 0) {
ui->scrollArea->verticalScrollBar()->setValue(ui->scrollArea->verticalScrollBar()->value() - dy);
}
} else if (e_type == QEvent::MouseButtonRelease && mouse_event->button() == Qt::LeftButton) {
m_pan_mode = false;
ui->scrollArea->setCursor(Qt::ArrowCursor);
}
}
return false;
}
void ImageViewer::openPrintImageDialog()
{
QPrinter printer;
QPrintPreviewDialog dialog(&printer);
connect(&dialog, &QPrintPreviewDialog::paintRequested, &dialog, [&](QPrinter* previewPrinter) {
QPainter painter(previewPrinter);
QRect rect = painter.viewport();
#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0)
QPixmap pixmap = *ui->labelView->pixmap();
#else
QPixmap pixmap = ui->labelView->pixmap(Qt::ReturnByValue);
#endif
QSize size = pixmap.size();
size.scale(rect.size(), Qt::KeepAspectRatio);
painter.setViewport(rect.x(), rect.y(), size.width(), size.height());
painter.setWindow(pixmap.rect());
painter.drawPixmap(0, 0, pixmap);
});
dialog.exec();
}
void ImageViewer::scaleToFitWindow(bool enabled)
{
// Enable/disable the automatic resizing of the label inside the scrollbar
ui->scrollArea->setWidgetResizable(enabled);
// When disabling the fit to window scaling, revert back to the original image size
if(!enabled) {
scaleImage(100);
} else {
ui->labelView->setMaximumSize(m_image_size.scaled(ui->scrollArea->viewport()->size(), Qt::KeepAspectRatio));
setSliderValueWithoutSignal(static_cast(ui->labelView->maximumWidth() / static_cast(m_image_size.width()) * 100));
}
}
void ImageViewer::setNoFitWithoutSignal()
{
if (ui->buttonFitToWindow->isChecked()) {
ui->buttonFitToWindow->blockSignals(true);
ui->scrollArea->setWidgetResizable(false);
ui->buttonFitToWindow->setChecked(false);
ui->buttonFitToWindow->blockSignals(false);
}
}
void ImageViewer::setSliderValueWithoutSignal(int value)
{
ui->sliderScale->blockSignals(true);
ui->sliderScale->setValue(value);
ui->sliderScale->blockSignals(false);
}
void ImageViewer::scaleImage(int scale)
{
// Clamp scale to the sliderScale min/max
scale = std::min(ui->sliderScale->maximum(), std::max(ui->sliderScale->minimum(), scale));
// Make sure the slider is updated when this is called programmatically
setSliderValueWithoutSignal(scale);
// Uncheck the fit to window button
setNoFitWithoutSignal();
// Update our scale factor
auto scale_factor = scale / 100.0;
// Resize the image
auto max_size_old = ui->labelView->maximumSize();
ui->labelView->setMaximumSize(m_image_size * scale_factor);
ui->labelView->resize(ui->labelView->maximumSize());
auto factor_change = ui->labelView->maximumWidth() / static_cast(max_size_old.width());
// Fix scroll bars to zoom into center of viewport instead of the upper left corner
const auto adjust_scrollbar = [](QScrollBar* scroll_bar, qreal factor) {
scroll_bar->setValue(static_cast(factor * scroll_bar->value() + ((factor - 1) * scroll_bar->pageStep() / 2)));
};
adjust_scrollbar(ui->scrollArea->horizontalScrollBar(), factor_change);
adjust_scrollbar(ui->scrollArea->verticalScrollBar(), factor_change);
}