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