git repos / SagoImageBrowser

blame: src/imageviewwidget.cpp

normal view · raw

61136b77 Poul Sander 2026-02-20 22:45 1
#include "imageviewwidget.h"
61136b77 Poul Sander 2026-02-20 22:45 2
61136b77 Poul Sander 2026-02-20 22:45 3
#include <QPainter>
61136b77 Poul Sander 2026-02-20 22:45 4
#include <QKeyEvent>
c8ae2669 Poul Sander 2026-02-22 17:52 5
#include <QMouseEvent>
61136b77 Poul Sander 2026-02-20 22:45 6
#include <QImageReader>
f61bf886 Poul Sander 2026-02-23 19:27 7
#include <QPalette>
c58dbdb7 Poul Sander 2026-02-22 17:49 8
#include <algorithm>
61136b77 Poul Sander 2026-02-20 22:45 9
61136b77 Poul Sander 2026-02-20 22:45 10
ImageViewWidget::ImageViewWidget(QWidget *parent)
61136b77 Poul Sander 2026-02-20 22:45 11
    : QWidget(parent)
61136b77 Poul Sander 2026-02-20 22:45 12
{
61136b77 Poul Sander 2026-02-20 22:45 13
    setFocusPolicy(Qt::StrongFocus);
f61bf886 Poul Sander 2026-02-23 19:27 14
    setAutoFillBackground(true);
f61bf886 Poul Sander 2026-02-23 19:27 15
    setBackgroundColor("black");
61136b77 Poul Sander 2026-02-20 22:45 16
}
61136b77 Poul Sander 2026-02-20 22:45 17
61136b77 Poul Sander 2026-02-20 22:45 18
void ImageViewWidget::setImage(const QString &path)
61136b77 Poul Sander 2026-02-20 22:45 19
{
61136b77 Poul Sander 2026-02-20 22:45 20
    QImageReader reader(path);
61136b77 Poul Sander 2026-02-20 22:45 21
    reader.setAutoTransform(true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 22
    reader.setDecideFormatFromContent(true);
61136b77 Poul Sander 2026-02-20 22:45 23
    QImage image = reader.read();
61136b77 Poul Sander 2026-02-20 22:45 24
e1e7f5a6 Poul Sander 2026-02-23 19:40 25
    if (!image.isNull()) {
e1e7f5a6 Poul Sander 2026-02-23 19:40 26
        // Ensure the image is in a high-quality format
e1e7f5a6 Poul Sander 2026-02-23 19:40 27
        if (image.format() != QImage::Format_RGB32 && image.format() != QImage::Format_ARGB32 && image.format() != QImage::Format_ARGB32_Premultiplied)
e1e7f5a6 Poul Sander 2026-02-23 19:40 28
            image = image.convertToFormat(QImage::Format_ARGB32);
61136b77 Poul Sander 2026-02-20 22:45 29
        m_pixmap = QPixmap::fromImage(image);
e1e7f5a6 Poul Sander 2026-02-23 19:40 30
    }
61136b77 Poul Sander 2026-02-20 22:45 31
    else
61136b77 Poul Sander 2026-02-20 22:45 32
        m_pixmap = QPixmap();
61136b77 Poul Sander 2026-02-20 22:45 33
c58dbdb7 Poul Sander 2026-02-22 17:49 34
    m_zoomMode = FitToScreen;
c58dbdb7 Poul Sander 2026-02-22 17:49 35
    m_zoomFactor = 1.0;
c8ae2669 Poul Sander 2026-02-22 17:52 36
    m_offset = QPoint(0, 0);
61136b77 Poul Sander 2026-02-20 22:45 37
    update();
61136b77 Poul Sander 2026-02-20 22:45 38
}
61136b77 Poul Sander 2026-02-20 22:45 39
f61bf886 Poul Sander 2026-02-23 19:27 40
void ImageViewWidget::setBackgroundColor(const QString &color)
f61bf886 Poul Sander 2026-02-23 19:27 41
{
f61bf886 Poul Sander 2026-02-23 19:27 42
    m_backgroundColor = color;
f61bf886 Poul Sander 2026-02-23 19:27 43
    QPalette pal = palette();
f61bf886 Poul Sander 2026-02-23 19:27 44
    pal.setColor(QPalette::Window, QColor(color));
f61bf886 Poul Sander 2026-02-23 19:27 45
    setPalette(pal);
f61bf886 Poul Sander 2026-02-23 19:27 46
    update();
f61bf886 Poul Sander 2026-02-23 19:27 47
}
f61bf886 Poul Sander 2026-02-23 19:27 48
61136b77 Poul Sander 2026-02-20 22:45 49
void ImageViewWidget::paintEvent(QPaintEvent *)
61136b77 Poul Sander 2026-02-20 22:45 50
{
61136b77 Poul Sander 2026-02-20 22:45 51
    if (m_pixmap.isNull())
61136b77 Poul Sander 2026-02-20 22:45 52
        return;
61136b77 Poul Sander 2026-02-20 22:45 53
61136b77 Poul Sander 2026-02-20 22:45 54
    QPainter painter(this);
e1e7f5a6 Poul Sander 2026-02-23 19:40 55
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 56
    painter.setRenderHint(QPainter::Antialiasing, true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 57
c58dbdb7 Poul Sander 2026-02-22 17:49 58
    QPixmap drawn;
c58dbdb7 Poul Sander 2026-02-22 17:49 59
c58dbdb7 Poul Sander 2026-02-22 17:49 60
    switch (m_zoomMode) {
c58dbdb7 Poul Sander 2026-02-22 17:49 61
    case FitToScreen:
c58dbdb7 Poul Sander 2026-02-22 17:49 62
        drawn = m_pixmap.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
c58dbdb7 Poul Sander 2026-02-22 17:49 63
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 64
    case OriginalSize:
c58dbdb7 Poul Sander 2026-02-22 17:49 65
        drawn = m_pixmap;
c58dbdb7 Poul Sander 2026-02-22 17:49 66
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 67
    case CustomZoom: {
c58dbdb7 Poul Sander 2026-02-22 17:49 68
        QSize target(static_cast<int>(m_pixmap.width() * m_zoomFactor),
c58dbdb7 Poul Sander 2026-02-22 17:49 69
                     static_cast<int>(m_pixmap.height() * m_zoomFactor));
c58dbdb7 Poul Sander 2026-02-22 17:49 70
        drawn = m_pixmap.scaled(target, Qt::KeepAspectRatio, Qt::SmoothTransformation);
c58dbdb7 Poul Sander 2026-02-22 17:49 71
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 72
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 73
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 74
c8ae2669 Poul Sander 2026-02-22 17:52 75
    clampOffset(drawn.width(), drawn.height());
c8ae2669 Poul Sander 2026-02-22 17:52 76
c8ae2669 Poul Sander 2026-02-22 17:52 77
    int x = (width()  - drawn.width())  / 2 + m_offset.x();
c8ae2669 Poul Sander 2026-02-22 17:52 78
    int y = (height() - drawn.height()) / 2 + m_offset.y();
c58dbdb7 Poul Sander 2026-02-22 17:49 79
    painter.drawPixmap(x, y, drawn);
61136b77 Poul Sander 2026-02-20 22:45 80
}
61136b77 Poul Sander 2026-02-20 22:45 81
61136b77 Poul Sander 2026-02-20 22:45 82
void ImageViewWidget::keyPressEvent(QKeyEvent *event)
61136b77 Poul Sander 2026-02-20 22:45 83
{
1035a476 Poul Sander 2026-02-23 19:30 84
    if (event->key() == Qt::Key_Escape || event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
61136b77 Poul Sander 2026-02-20 22:45 85
    {
61136b77 Poul Sander 2026-02-20 22:45 86
        emit closeRequested();
61136b77 Poul Sander 2026-02-20 22:45 87
        event->accept();
61136b77 Poul Sander 2026-02-20 22:45 88
        return;
61136b77 Poul Sander 2026-02-20 22:45 89
    }
61136b77 Poul Sander 2026-02-20 22:45 90
1ffc1962 Poul Sander 2026-02-20 23:41 91
    if (event->key() == Qt::Key_PageDown)
1ffc1962 Poul Sander 2026-02-20 23:41 92
    {
1ffc1962 Poul Sander 2026-02-20 23:41 93
        emit nextRequested();
1ffc1962 Poul Sander 2026-02-20 23:41 94
        event->accept();
1ffc1962 Poul Sander 2026-02-20 23:41 95
        return;
1ffc1962 Poul Sander 2026-02-20 23:41 96
    }
1ffc1962 Poul Sander 2026-02-20 23:41 97
1ffc1962 Poul Sander 2026-02-20 23:41 98
    if (event->key() == Qt::Key_PageUp)
1ffc1962 Poul Sander 2026-02-20 23:41 99
    {
1ffc1962 Poul Sander 2026-02-20 23:41 100
        emit previousRequested();
1ffc1962 Poul Sander 2026-02-20 23:41 101
        event->accept();
1ffc1962 Poul Sander 2026-02-20 23:41 102
        return;
1ffc1962 Poul Sander 2026-02-20 23:41 103
    }
1ffc1962 Poul Sander 2026-02-20 23:41 104
c8ae2669 Poul Sander 2026-02-22 17:52 105
    // Arrow keys for panning
c8ae2669 Poul Sander 2026-02-22 17:52 106
    constexpr int panStep = 50;
c8ae2669 Poul Sander 2026-02-22 17:52 107
    if (event->key() == Qt::Key_Left)
c8ae2669 Poul Sander 2026-02-22 17:52 108
    {
c8ae2669 Poul Sander 2026-02-22 17:52 109
        m_offset.rx() += panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 110
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 111
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 112
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 113
    }
c8ae2669 Poul Sander 2026-02-22 17:52 114
    if (event->key() == Qt::Key_Right)
c8ae2669 Poul Sander 2026-02-22 17:52 115
    {
c8ae2669 Poul Sander 2026-02-22 17:52 116
        m_offset.rx() -= panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 117
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 118
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 119
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 120
    }
c8ae2669 Poul Sander 2026-02-22 17:52 121
    if (event->key() == Qt::Key_Up)
c8ae2669 Poul Sander 2026-02-22 17:52 122
    {
c8ae2669 Poul Sander 2026-02-22 17:52 123
        m_offset.ry() += panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 124
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 125
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 126
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 127
    }
c8ae2669 Poul Sander 2026-02-22 17:52 128
    if (event->key() == Qt::Key_Down)
c8ae2669 Poul Sander 2026-02-22 17:52 129
    {
c8ae2669 Poul Sander 2026-02-22 17:52 130
        m_offset.ry() -= panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 131
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 132
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 133
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 134
    }
c8ae2669 Poul Sander 2026-02-22 17:52 135
c58dbdb7 Poul Sander 2026-02-22 17:49 136
    if (event->key() == Qt::Key_Slash)
c58dbdb7 Poul Sander 2026-02-22 17:49 137
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 138
        zoomOriginal();
c58dbdb7 Poul Sander 2026-02-22 17:49 139
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 140
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 141
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 142
c58dbdb7 Poul Sander 2026-02-22 17:49 143
    if (event->key() == Qt::Key_Asterisk)
c58dbdb7 Poul Sander 2026-02-22 17:49 144
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 145
        zoomFitToScreen();
c58dbdb7 Poul Sander 2026-02-22 17:49 146
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 147
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 148
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 149
c58dbdb7 Poul Sander 2026-02-22 17:49 150
    if (event->key() == Qt::Key_Plus)
c58dbdb7 Poul Sander 2026-02-22 17:49 151
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 152
        zoomIn();
c58dbdb7 Poul Sander 2026-02-22 17:49 153
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 154
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 155
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 156
c58dbdb7 Poul Sander 2026-02-22 17:49 157
    if (event->key() == Qt::Key_Minus)
c58dbdb7 Poul Sander 2026-02-22 17:49 158
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 159
        zoomOut();
c58dbdb7 Poul Sander 2026-02-22 17:49 160
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 161
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 162
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 163
61136b77 Poul Sander 2026-02-20 22:45 164
    QWidget::keyPressEvent(event);
61136b77 Poul Sander 2026-02-20 22:45 165
}
c58dbdb7 Poul Sander 2026-02-22 17:49 166
c58dbdb7 Poul Sander 2026-02-22 17:49 167
void ImageViewWidget::zoomIn()
c58dbdb7 Poul Sander 2026-02-22 17:49 168
{
c58dbdb7 Poul Sander 2026-02-22 17:49 169
    if (m_zoomMode == FitToScreen) {
c58dbdb7 Poul Sander 2026-02-22 17:49 170
        // Calculate the current effective scale so zooming feels continuous
c58dbdb7 Poul Sander 2026-02-22 17:49 171
        double sx = static_cast<double>(width()) / m_pixmap.width();
c58dbdb7 Poul Sander 2026-02-22 17:49 172
        double sy = static_cast<double>(height()) / m_pixmap.height();
c58dbdb7 Poul Sander 2026-02-22 17:49 173
        m_zoomFactor = std::min(sx, sy);
c58dbdb7 Poul Sander 2026-02-22 17:49 174
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 175
    m_zoomFactor *= 1.25;
c58dbdb7 Poul Sander 2026-02-22 17:49 176
    m_zoomMode = CustomZoom;
c58dbdb7 Poul Sander 2026-02-22 17:49 177
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 178
}
c58dbdb7 Poul Sander 2026-02-22 17:49 179
c58dbdb7 Poul Sander 2026-02-22 17:49 180
void ImageViewWidget::zoomOut()
c58dbdb7 Poul Sander 2026-02-22 17:49 181
{
c58dbdb7 Poul Sander 2026-02-22 17:49 182
    if (m_zoomMode == FitToScreen) {
c58dbdb7 Poul Sander 2026-02-22 17:49 183
        double sx = static_cast<double>(width()) / m_pixmap.width();
c58dbdb7 Poul Sander 2026-02-22 17:49 184
        double sy = static_cast<double>(height()) / m_pixmap.height();
c58dbdb7 Poul Sander 2026-02-22 17:49 185
        m_zoomFactor = std::min(sx, sy);
c58dbdb7 Poul Sander 2026-02-22 17:49 186
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 187
    m_zoomFactor /= 1.25;
c58dbdb7 Poul Sander 2026-02-22 17:49 188
    if (m_zoomFactor < 0.01)
c58dbdb7 Poul Sander 2026-02-22 17:49 189
        m_zoomFactor = 0.01;
c58dbdb7 Poul Sander 2026-02-22 17:49 190
    m_zoomMode = CustomZoom;
c58dbdb7 Poul Sander 2026-02-22 17:49 191
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 192
}
c58dbdb7 Poul Sander 2026-02-22 17:49 193
c58dbdb7 Poul Sander 2026-02-22 17:49 194
void ImageViewWidget::zoomOriginal()
c58dbdb7 Poul Sander 2026-02-22 17:49 195
{
c58dbdb7 Poul Sander 2026-02-22 17:49 196
    m_zoomMode = OriginalSize;
c58dbdb7 Poul Sander 2026-02-22 17:49 197
    m_zoomFactor = 1.0;
c58dbdb7 Poul Sander 2026-02-22 17:49 198
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 199
}
c58dbdb7 Poul Sander 2026-02-22 17:49 200
c58dbdb7 Poul Sander 2026-02-22 17:49 201
void ImageViewWidget::zoomFitToScreen()
c58dbdb7 Poul Sander 2026-02-22 17:49 202
{
c58dbdb7 Poul Sander 2026-02-22 17:49 203
    m_zoomMode = FitToScreen;
c8ae2669 Poul Sander 2026-02-22 17:52 204
    m_offset = QPoint(0, 0);
c58dbdb7 Poul Sander 2026-02-22 17:49 205
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 206
}
c8ae2669 Poul Sander 2026-02-22 17:52 207
c8ae2669 Poul Sander 2026-02-22 17:52 208
void ImageViewWidget::mousePressEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 209
{
c8ae2669 Poul Sander 2026-02-22 17:52 210
    if (event->button() == Qt::LeftButton) {
c8ae2669 Poul Sander 2026-02-22 17:52 211
        m_dragging = true;
c8ae2669 Poul Sander 2026-02-22 17:52 212
        m_dragStart = event->pos();
c8ae2669 Poul Sander 2026-02-22 17:52 213
        m_offsetAtDragStart = m_offset;
c8ae2669 Poul Sander 2026-02-22 17:52 214
        setCursor(Qt::ClosedHandCursor);
c8ae2669 Poul Sander 2026-02-22 17:52 215
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 216
    }
c8ae2669 Poul Sander 2026-02-22 17:52 217
}
c8ae2669 Poul Sander 2026-02-22 17:52 218
c8ae2669 Poul Sander 2026-02-22 17:52 219
void ImageViewWidget::mouseMoveEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 220
{
c8ae2669 Poul Sander 2026-02-22 17:52 221
    if (m_dragging) {
c8ae2669 Poul Sander 2026-02-22 17:52 222
        m_offset = m_offsetAtDragStart + (event->pos() - m_dragStart);
c8ae2669 Poul Sander 2026-02-22 17:52 223
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 224
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 225
    }
c8ae2669 Poul Sander 2026-02-22 17:52 226
}
c8ae2669 Poul Sander 2026-02-22 17:52 227
c8ae2669 Poul Sander 2026-02-22 17:52 228
void ImageViewWidget::mouseReleaseEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 229
{
c8ae2669 Poul Sander 2026-02-22 17:52 230
    if (event->button() == Qt::LeftButton && m_dragging) {
c8ae2669 Poul Sander 2026-02-22 17:52 231
        m_dragging = false;
c8ae2669 Poul Sander 2026-02-22 17:52 232
        setCursor(Qt::ArrowCursor);
c8ae2669 Poul Sander 2026-02-22 17:52 233
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 234
    }
c8ae2669 Poul Sander 2026-02-22 17:52 235
}
c8ae2669 Poul Sander 2026-02-22 17:52 236
1035a476 Poul Sander 2026-02-23 19:30 237
void ImageViewWidget::mouseDoubleClickEvent(QMouseEvent *event)
1035a476 Poul Sander 2026-02-23 19:30 238
{
1035a476 Poul Sander 2026-02-23 19:30 239
    if (event->button() == Qt::LeftButton) {
1035a476 Poul Sander 2026-02-23 19:30 240
        emit closeRequested();
1035a476 Poul Sander 2026-02-23 19:30 241
        event->accept();
1035a476 Poul Sander 2026-02-23 19:30 242
    }
1035a476 Poul Sander 2026-02-23 19:30 243
}
1035a476 Poul Sander 2026-02-23 19:30 244
c8ae2669 Poul Sander 2026-02-22 17:52 245
void ImageViewWidget::clampOffset(int imgW, int imgH)
c8ae2669 Poul Sander 2026-02-22 17:52 246
{
c8ae2669 Poul Sander 2026-02-22 17:52 247
    // Only allow panning when the drawn image exceeds the widget
c8ae2669 Poul Sander 2026-02-22 17:52 248
    int overflowX = imgW - width();
c8ae2669 Poul Sander 2026-02-22 17:52 249
    int overflowY = imgH - height();
c8ae2669 Poul Sander 2026-02-22 17:52 250
c8ae2669 Poul Sander 2026-02-22 17:52 251
    if (overflowX <= 0)
c8ae2669 Poul Sander 2026-02-22 17:52 252
        m_offset.rx() = 0;
c8ae2669 Poul Sander 2026-02-22 17:52 253
    else {
c8ae2669 Poul Sander 2026-02-22 17:52 254
        int limit = overflowX / 2;
c8ae2669 Poul Sander 2026-02-22 17:52 255
        m_offset.rx() = std::clamp(m_offset.x(), -limit, limit);
c8ae2669 Poul Sander 2026-02-22 17:52 256
    }
c8ae2669 Poul Sander 2026-02-22 17:52 257
c8ae2669 Poul Sander 2026-02-22 17:52 258
    if (overflowY <= 0)
c8ae2669 Poul Sander 2026-02-22 17:52 259
        m_offset.ry() = 0;
c8ae2669 Poul Sander 2026-02-22 17:52 260
    else {
c8ae2669 Poul Sander 2026-02-22 17:52 261
        int limit = overflowY / 2;
c8ae2669 Poul Sander 2026-02-22 17:52 262
        m_offset.ry() = std::clamp(m_offset.y(), -limit, limit);
c8ae2669 Poul Sander 2026-02-22 17:52 263
    }
c8ae2669 Poul Sander 2026-02-22 17:52 264
}
1970-01-01 00:00 265