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