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>
58103277 Poul Sander 2026-03-01 22:53 9
#include <iostream>
58103277 Poul Sander 2026-03-01 22:53 10
58103277 Poul Sander 2026-03-01 22:53 11
// --- ImageLoadWorker ---
58103277 Poul Sander 2026-03-01 22:53 12
58103277 Poul Sander 2026-03-01 22:53 13
ImageLoadWorker::ImageLoadWorker(const QString &path, QObject *parent)
58103277 Poul Sander 2026-03-01 22:53 14
    : QThread(parent), m_path(path)
58103277 Poul Sander 2026-03-01 22:53 15
{
58103277 Poul Sander 2026-03-01 22:53 16
}
58103277 Poul Sander 2026-03-01 22:53 17
58103277 Poul Sander 2026-03-01 22:53 18
void ImageLoadWorker::run()
58103277 Poul Sander 2026-03-01 22:53 19
{
58103277 Poul Sander 2026-03-01 22:53 20
    QImageReader reader(m_path);
58103277 Poul Sander 2026-03-01 22:53 21
    reader.setAutoTransform(true);
58103277 Poul Sander 2026-03-01 22:53 22
    reader.setDecideFormatFromContent(true);
58103277 Poul Sander 2026-03-01 22:53 23
    reader.setAllocationLimit(0);
58103277 Poul Sander 2026-03-01 22:53 24
    QImage image = reader.read();
58103277 Poul Sander 2026-03-01 22:53 25
58103277 Poul Sander 2026-03-01 22:53 26
    QPixmap pixmap;
58103277 Poul Sander 2026-03-01 22:53 27
    if (!image.isNull()) {
58103277 Poul Sander 2026-03-01 22:53 28
        if (image.format() != QImage::Format_RGB32
58103277 Poul Sander 2026-03-01 22:53 29
            && image.format() != QImage::Format_ARGB32
58103277 Poul Sander 2026-03-01 22:53 30
            && image.format() != QImage::Format_ARGB32_Premultiplied)
58103277 Poul Sander 2026-03-01 22:53 31
            image = image.convertToFormat(QImage::Format_ARGB32);
58103277 Poul Sander 2026-03-01 22:53 32
        pixmap = QPixmap::fromImage(image);
58103277 Poul Sander 2026-03-01 22:53 33
    }
58103277 Poul Sander 2026-03-01 22:53 34
    emit imageLoaded(m_path, pixmap);
58103277 Poul Sander 2026-03-01 22:53 35
}
58103277 Poul Sander 2026-03-01 22:53 36
58103277 Poul Sander 2026-03-01 22:53 37
// --- ImageViewWidget ---
61136b77 Poul Sander 2026-02-20 22:45 38
61136b77 Poul Sander 2026-02-20 22:45 39
ImageViewWidget::ImageViewWidget(QWidget *parent)
61136b77 Poul Sander 2026-02-20 22:45 40
    : QWidget(parent)
61136b77 Poul Sander 2026-02-20 22:45 41
{
61136b77 Poul Sander 2026-02-20 22:45 42
    setFocusPolicy(Qt::StrongFocus);
f61bf886 Poul Sander 2026-02-23 19:27 43
    setAutoFillBackground(true);
f61bf886 Poul Sander 2026-02-23 19:27 44
    setBackgroundColor("black");
61136b77 Poul Sander 2026-02-20 22:45 45
}
61136b77 Poul Sander 2026-02-20 22:45 46
58103277 Poul Sander 2026-03-01 22:53 47
QPixmap ImageViewWidget::loadImageFromDisk(const QString &path)
61136b77 Poul Sander 2026-02-20 22:45 48
{
61136b77 Poul Sander 2026-02-20 22:45 49
    QImageReader reader(path);
61136b77 Poul Sander 2026-02-20 22:45 50
    reader.setAutoTransform(true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 51
    reader.setDecideFormatFromContent(true);
7889168c Poul Sander 2026-02-26 18:27 52
    reader.setAllocationLimit(0);
61136b77 Poul Sander 2026-02-20 22:45 53
    QImage image = reader.read();
61136b77 Poul Sander 2026-02-20 22:45 54
e1e7f5a6 Poul Sander 2026-02-23 19:40 55
    if (!image.isNull()) {
58103277 Poul Sander 2026-03-01 22:53 56
        if (image.format() != QImage::Format_RGB32
58103277 Poul Sander 2026-03-01 22:53 57
            && image.format() != QImage::Format_ARGB32
58103277 Poul Sander 2026-03-01 22:53 58
            && image.format() != QImage::Format_ARGB32_Premultiplied)
e1e7f5a6 Poul Sander 2026-02-23 19:40 59
            image = image.convertToFormat(QImage::Format_ARGB32);
58103277 Poul Sander 2026-03-01 22:53 60
        return QPixmap::fromImage(image);
58103277 Poul Sander 2026-03-01 22:53 61
    }
58103277 Poul Sander 2026-03-01 22:53 62
    return QPixmap();
58103277 Poul Sander 2026-03-01 22:53 63
}
58103277 Poul Sander 2026-03-01 22:53 64
58103277 Poul Sander 2026-03-01 22:53 65
void ImageViewWidget::setImage(const QString &path)
58103277 Poul Sander 2026-03-01 22:53 66
{
58103277 Poul Sander 2026-03-01 22:53 67
    m_currentPath = path;
58103277 Poul Sander 2026-03-01 22:53 68
58103277 Poul Sander 2026-03-01 22:53 69
    // Check cache first
58103277 Poul Sander 2026-03-01 22:53 70
    if (m_cache.contains(path)) {
58103277 Poul Sander 2026-03-01 22:53 71
        m_pixmap = m_cache[path];
58103277 Poul Sander 2026-03-01 22:53 72
    } else {
58103277 Poul Sander 2026-03-01 22:53 73
        m_pixmap = loadImageFromDisk(path);
58103277 Poul Sander 2026-03-01 22:53 74
        m_cache[path] = m_pixmap;
e1e7f5a6 Poul Sander 2026-02-23 19:40 75
    }
61136b77 Poul Sander 2026-02-20 22:45 76
c58dbdb7 Poul Sander 2026-02-22 17:49 77
    m_zoomMode = FitToScreen;
c58dbdb7 Poul Sander 2026-02-22 17:49 78
    m_zoomFactor = 1.0;
c8ae2669 Poul Sander 2026-02-22 17:52 79
    m_offset = QPoint(0, 0);
61136b77 Poul Sander 2026-02-20 22:45 80
    update();
58103277 Poul Sander 2026-03-01 22:53 81
58103277 Poul Sander 2026-03-01 22:53 82
    // Trigger prefetch of neighbors if they have been set
58103277 Poul Sander 2026-03-01 22:53 83
    if (!m_neighborPaths.isEmpty()) {
58103277 Poul Sander 2026-03-01 22:53 84
        // Evict entries that are no longer in the neighbor window
58103277 Poul Sander 2026-03-01 22:53 85
        QSet<QString> keep(m_neighborPaths.begin(), m_neighborPaths.end());
58103277 Poul Sander 2026-03-01 22:53 86
        keep.insert(m_currentPath);
58103277 Poul Sander 2026-03-01 22:53 87
        for (auto it = m_cache.begin(); it != m_cache.end(); ) {
58103277 Poul Sander 2026-03-01 22:53 88
            if (!keep.contains(it.key()))
58103277 Poul Sander 2026-03-01 22:53 89
                it = m_cache.erase(it);
58103277 Poul Sander 2026-03-01 22:53 90
            else
58103277 Poul Sander 2026-03-01 22:53 91
                ++it;
58103277 Poul Sander 2026-03-01 22:53 92
        }
58103277 Poul Sander 2026-03-01 22:53 93
58103277 Poul Sander 2026-03-01 22:53 94
        // Prefetch neighbors that are not yet cached
58103277 Poul Sander 2026-03-01 22:53 95
        for (const QString &neighbor : m_neighborPaths) {
58103277 Poul Sander 2026-03-01 22:53 96
            prefetchImage(neighbor);
58103277 Poul Sander 2026-03-01 22:53 97
        }
58103277 Poul Sander 2026-03-01 22:53 98
    }
58103277 Poul Sander 2026-03-01 22:53 99
}
58103277 Poul Sander 2026-03-01 22:53 100
58103277 Poul Sander 2026-03-01 22:53 101
void ImageViewWidget::prefetchImage(const QString &path)
58103277 Poul Sander 2026-03-01 22:53 102
{
58103277 Poul Sander 2026-03-01 22:53 103
    if (m_cache.contains(path) || m_pendingLoads.contains(path))
58103277 Poul Sander 2026-03-01 22:53 104
        return;
58103277 Poul Sander 2026-03-01 22:53 105
58103277 Poul Sander 2026-03-01 22:53 106
    m_pendingLoads.insert(path);
58103277 Poul Sander 2026-03-01 22:53 107
    auto *worker = new ImageLoadWorker(path, this);
58103277 Poul Sander 2026-03-01 22:53 108
    connect(worker, &ImageLoadWorker::imageLoaded, this, &ImageViewWidget::onImageLoaded);
58103277 Poul Sander 2026-03-01 22:53 109
    connect(worker, &QThread::finished, worker, &QObject::deleteLater);
58103277 Poul Sander 2026-03-01 22:53 110
    worker->start();
58103277 Poul Sander 2026-03-01 22:53 111
}
58103277 Poul Sander 2026-03-01 22:53 112
58103277 Poul Sander 2026-03-01 22:53 113
void ImageViewWidget::onImageLoaded(const QString &path, const QPixmap &pixmap)
58103277 Poul Sander 2026-03-01 22:53 114
{
58103277 Poul Sander 2026-03-01 22:53 115
    m_pendingLoads.remove(path);
58103277 Poul Sander 2026-03-01 22:53 116
58103277 Poul Sander 2026-03-01 22:53 117
    // Only cache if path is still relevant (current or a neighbor)
58103277 Poul Sander 2026-03-01 22:53 118
    QSet<QString> keep(m_neighborPaths.begin(), m_neighborPaths.end());
58103277 Poul Sander 2026-03-01 22:53 119
    keep.insert(m_currentPath);
58103277 Poul Sander 2026-03-01 22:53 120
    if (keep.contains(path)) {
58103277 Poul Sander 2026-03-01 22:53 121
        m_cache[path] = pixmap;
58103277 Poul Sander 2026-03-01 22:53 122
    }
58103277 Poul Sander 2026-03-01 22:53 123
}
58103277 Poul Sander 2026-03-01 22:53 124
58103277 Poul Sander 2026-03-01 22:53 125
void ImageViewWidget::setNeighborPaths(const QStringList &paths)
58103277 Poul Sander 2026-03-01 22:53 126
{
58103277 Poul Sander 2026-03-01 22:53 127
    m_neighborPaths = paths;
58103277 Poul Sander 2026-03-01 22:53 128
}
58103277 Poul Sander 2026-03-01 22:53 129
58103277 Poul Sander 2026-03-01 22:53 130
void ImageViewWidget::clearCache()
58103277 Poul Sander 2026-03-01 22:53 131
{
58103277 Poul Sander 2026-03-01 22:53 132
    m_cache.clear();
58103277 Poul Sander 2026-03-01 22:53 133
    m_neighborPaths.clear();
61136b77 Poul Sander 2026-02-20 22:45 134
}
61136b77 Poul Sander 2026-02-20 22:45 135
f61bf886 Poul Sander 2026-02-23 19:27 136
void ImageViewWidget::setBackgroundColor(const QString &color)
f61bf886 Poul Sander 2026-02-23 19:27 137
{
f61bf886 Poul Sander 2026-02-23 19:27 138
    m_backgroundColor = color;
f61bf886 Poul Sander 2026-02-23 19:27 139
    QPalette pal = palette();
f61bf886 Poul Sander 2026-02-23 19:27 140
    pal.setColor(QPalette::Window, QColor(color));
f61bf886 Poul Sander 2026-02-23 19:27 141
    setPalette(pal);
f61bf886 Poul Sander 2026-02-23 19:27 142
    update();
f61bf886 Poul Sander 2026-02-23 19:27 143
}
f61bf886 Poul Sander 2026-02-23 19:27 144
61136b77 Poul Sander 2026-02-20 22:45 145
void ImageViewWidget::paintEvent(QPaintEvent *)
61136b77 Poul Sander 2026-02-20 22:45 146
{
61136b77 Poul Sander 2026-02-20 22:45 147
    if (m_pixmap.isNull())
61136b77 Poul Sander 2026-02-20 22:45 148
        return;
61136b77 Poul Sander 2026-02-20 22:45 149
61136b77 Poul Sander 2026-02-20 22:45 150
    QPainter painter(this);
e1e7f5a6 Poul Sander 2026-02-23 19:40 151
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 152
    painter.setRenderHint(QPainter::Antialiasing, true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 153
c58dbdb7 Poul Sander 2026-02-22 17:49 154
    QPixmap drawn;
c58dbdb7 Poul Sander 2026-02-22 17:49 155
c58dbdb7 Poul Sander 2026-02-22 17:49 156
    switch (m_zoomMode) {
c58dbdb7 Poul Sander 2026-02-22 17:49 157
    case FitToScreen:
c58dbdb7 Poul Sander 2026-02-22 17:49 158
        drawn = m_pixmap.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
c58dbdb7 Poul Sander 2026-02-22 17:49 159
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 160
    case OriginalSize:
c58dbdb7 Poul Sander 2026-02-22 17:49 161
        drawn = m_pixmap;
c58dbdb7 Poul Sander 2026-02-22 17:49 162
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 163
    case CustomZoom: {
c58dbdb7 Poul Sander 2026-02-22 17:49 164
        QSize target(static_cast<int>(m_pixmap.width() * m_zoomFactor),
c58dbdb7 Poul Sander 2026-02-22 17:49 165
                     static_cast<int>(m_pixmap.height() * m_zoomFactor));
c58dbdb7 Poul Sander 2026-02-22 17:49 166
        drawn = m_pixmap.scaled(target, Qt::KeepAspectRatio, Qt::SmoothTransformation);
c58dbdb7 Poul Sander 2026-02-22 17:49 167
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 168
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 169
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 170
c8ae2669 Poul Sander 2026-02-22 17:52 171
    clampOffset(drawn.width(), drawn.height());
c8ae2669 Poul Sander 2026-02-22 17:52 172
c8ae2669 Poul Sander 2026-02-22 17:52 173
    int x = (width()  - drawn.width())  / 2 + m_offset.x();
c8ae2669 Poul Sander 2026-02-22 17:52 174
    int y = (height() - drawn.height()) / 2 + m_offset.y();
c58dbdb7 Poul Sander 2026-02-22 17:49 175
    painter.drawPixmap(x, y, drawn);
61136b77 Poul Sander 2026-02-20 22:45 176
}
61136b77 Poul Sander 2026-02-20 22:45 177
61136b77 Poul Sander 2026-02-20 22:45 178
void ImageViewWidget::keyPressEvent(QKeyEvent *event)
61136b77 Poul Sander 2026-02-20 22:45 179
{
1035a476 Poul Sander 2026-02-23 19:30 180
    if (event->key() == Qt::Key_Escape || event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
61136b77 Poul Sander 2026-02-20 22:45 181
    {
61136b77 Poul Sander 2026-02-20 22:45 182
        emit closeRequested();
61136b77 Poul Sander 2026-02-20 22:45 183
        event->accept();
61136b77 Poul Sander 2026-02-20 22:45 184
        return;
61136b77 Poul Sander 2026-02-20 22:45 185
    }
61136b77 Poul Sander 2026-02-20 22:45 186
1ffc1962 Poul Sander 2026-02-20 23:41 187
    if (event->key() == Qt::Key_PageDown)
1ffc1962 Poul Sander 2026-02-20 23:41 188
    {
1ffc1962 Poul Sander 2026-02-20 23:41 189
        emit nextRequested();
1ffc1962 Poul Sander 2026-02-20 23:41 190
        event->accept();
1ffc1962 Poul Sander 2026-02-20 23:41 191
        return;
1ffc1962 Poul Sander 2026-02-20 23:41 192
    }
1ffc1962 Poul Sander 2026-02-20 23:41 193
1ffc1962 Poul Sander 2026-02-20 23:41 194
    if (event->key() == Qt::Key_PageUp)
1ffc1962 Poul Sander 2026-02-20 23:41 195
    {
1ffc1962 Poul Sander 2026-02-20 23:41 196
        emit previousRequested();
1ffc1962 Poul Sander 2026-02-20 23:41 197
        event->accept();
1ffc1962 Poul Sander 2026-02-20 23:41 198
        return;
1ffc1962 Poul Sander 2026-02-20 23:41 199
    }
1ffc1962 Poul Sander 2026-02-20 23:41 200
c8ae2669 Poul Sander 2026-02-22 17:52 201
    // Arrow keys for panning
c8ae2669 Poul Sander 2026-02-22 17:52 202
    constexpr int panStep = 50;
c8ae2669 Poul Sander 2026-02-22 17:52 203
    if (event->key() == Qt::Key_Left)
c8ae2669 Poul Sander 2026-02-22 17:52 204
    {
c8ae2669 Poul Sander 2026-02-22 17:52 205
        m_offset.rx() += panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 206
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 207
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 208
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 209
    }
c8ae2669 Poul Sander 2026-02-22 17:52 210
    if (event->key() == Qt::Key_Right)
c8ae2669 Poul Sander 2026-02-22 17:52 211
    {
c8ae2669 Poul Sander 2026-02-22 17:52 212
        m_offset.rx() -= panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 213
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 214
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 215
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 216
    }
c8ae2669 Poul Sander 2026-02-22 17:52 217
    if (event->key() == Qt::Key_Up)
c8ae2669 Poul Sander 2026-02-22 17:52 218
    {
c8ae2669 Poul Sander 2026-02-22 17:52 219
        m_offset.ry() += panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 220
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 221
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 222
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 223
    }
c8ae2669 Poul Sander 2026-02-22 17:52 224
    if (event->key() == Qt::Key_Down)
c8ae2669 Poul Sander 2026-02-22 17:52 225
    {
c8ae2669 Poul Sander 2026-02-22 17:52 226
        m_offset.ry() -= panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 227
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 228
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 229
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 230
    }
c8ae2669 Poul Sander 2026-02-22 17:52 231
c58dbdb7 Poul Sander 2026-02-22 17:49 232
    if (event->key() == Qt::Key_Slash)
c58dbdb7 Poul Sander 2026-02-22 17:49 233
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 234
        zoomOriginal();
c58dbdb7 Poul Sander 2026-02-22 17:49 235
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 236
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 237
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 238
c58dbdb7 Poul Sander 2026-02-22 17:49 239
    if (event->key() == Qt::Key_Asterisk)
c58dbdb7 Poul Sander 2026-02-22 17:49 240
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 241
        zoomFitToScreen();
c58dbdb7 Poul Sander 2026-02-22 17:49 242
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 243
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 244
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 245
c58dbdb7 Poul Sander 2026-02-22 17:49 246
    if (event->key() == Qt::Key_Plus)
c58dbdb7 Poul Sander 2026-02-22 17:49 247
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 248
        zoomIn();
c58dbdb7 Poul Sander 2026-02-22 17:49 249
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 250
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 251
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 252
c58dbdb7 Poul Sander 2026-02-22 17:49 253
    if (event->key() == Qt::Key_Minus)
c58dbdb7 Poul Sander 2026-02-22 17:49 254
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 255
        zoomOut();
c58dbdb7 Poul Sander 2026-02-22 17:49 256
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 257
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 258
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 259
61136b77 Poul Sander 2026-02-20 22:45 260
    QWidget::keyPressEvent(event);
61136b77 Poul Sander 2026-02-20 22:45 261
}
c58dbdb7 Poul Sander 2026-02-22 17:49 262
c58dbdb7 Poul Sander 2026-02-22 17:49 263
void ImageViewWidget::zoomIn()
c58dbdb7 Poul Sander 2026-02-22 17:49 264
{
c58dbdb7 Poul Sander 2026-02-22 17:49 265
    if (m_zoomMode == FitToScreen) {
c58dbdb7 Poul Sander 2026-02-22 17:49 266
        // Calculate the current effective scale so zooming feels continuous
c58dbdb7 Poul Sander 2026-02-22 17:49 267
        double sx = static_cast<double>(width()) / m_pixmap.width();
c58dbdb7 Poul Sander 2026-02-22 17:49 268
        double sy = static_cast<double>(height()) / m_pixmap.height();
c58dbdb7 Poul Sander 2026-02-22 17:49 269
        m_zoomFactor = std::min(sx, sy);
c58dbdb7 Poul Sander 2026-02-22 17:49 270
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 271
    m_zoomFactor *= 1.25;
c58dbdb7 Poul Sander 2026-02-22 17:49 272
    m_zoomMode = CustomZoom;
c58dbdb7 Poul Sander 2026-02-22 17:49 273
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 274
}
c58dbdb7 Poul Sander 2026-02-22 17:49 275
c58dbdb7 Poul Sander 2026-02-22 17:49 276
void ImageViewWidget::zoomOut()
c58dbdb7 Poul Sander 2026-02-22 17:49 277
{
c58dbdb7 Poul Sander 2026-02-22 17:49 278
    if (m_zoomMode == FitToScreen) {
c58dbdb7 Poul Sander 2026-02-22 17:49 279
        double sx = static_cast<double>(width()) / m_pixmap.width();
c58dbdb7 Poul Sander 2026-02-22 17:49 280
        double sy = static_cast<double>(height()) / m_pixmap.height();
c58dbdb7 Poul Sander 2026-02-22 17:49 281
        m_zoomFactor = std::min(sx, sy);
c58dbdb7 Poul Sander 2026-02-22 17:49 282
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 283
    m_zoomFactor /= 1.25;
c58dbdb7 Poul Sander 2026-02-22 17:49 284
    if (m_zoomFactor < 0.01)
c58dbdb7 Poul Sander 2026-02-22 17:49 285
        m_zoomFactor = 0.01;
c58dbdb7 Poul Sander 2026-02-22 17:49 286
    m_zoomMode = CustomZoom;
c58dbdb7 Poul Sander 2026-02-22 17:49 287
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 288
}
c58dbdb7 Poul Sander 2026-02-22 17:49 289
c58dbdb7 Poul Sander 2026-02-22 17:49 290
void ImageViewWidget::zoomOriginal()
c58dbdb7 Poul Sander 2026-02-22 17:49 291
{
c58dbdb7 Poul Sander 2026-02-22 17:49 292
    m_zoomMode = OriginalSize;
c58dbdb7 Poul Sander 2026-02-22 17:49 293
    m_zoomFactor = 1.0;
c58dbdb7 Poul Sander 2026-02-22 17:49 294
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 295
}
c58dbdb7 Poul Sander 2026-02-22 17:49 296
c58dbdb7 Poul Sander 2026-02-22 17:49 297
void ImageViewWidget::zoomFitToScreen()
c58dbdb7 Poul Sander 2026-02-22 17:49 298
{
c58dbdb7 Poul Sander 2026-02-22 17:49 299
    m_zoomMode = FitToScreen;
c8ae2669 Poul Sander 2026-02-22 17:52 300
    m_offset = QPoint(0, 0);
c58dbdb7 Poul Sander 2026-02-22 17:49 301
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 302
}
c8ae2669 Poul Sander 2026-02-22 17:52 303
c8ae2669 Poul Sander 2026-02-22 17:52 304
void ImageViewWidget::mousePressEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 305
{
c8ae2669 Poul Sander 2026-02-22 17:52 306
    if (event->button() == Qt::LeftButton) {
c8ae2669 Poul Sander 2026-02-22 17:52 307
        m_dragging = true;
c8ae2669 Poul Sander 2026-02-22 17:52 308
        m_dragStart = event->pos();
c8ae2669 Poul Sander 2026-02-22 17:52 309
        m_offsetAtDragStart = m_offset;
c8ae2669 Poul Sander 2026-02-22 17:52 310
        setCursor(Qt::ClosedHandCursor);
c8ae2669 Poul Sander 2026-02-22 17:52 311
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 312
    }
c8ae2669 Poul Sander 2026-02-22 17:52 313
}
c8ae2669 Poul Sander 2026-02-22 17:52 314
c8ae2669 Poul Sander 2026-02-22 17:52 315
void ImageViewWidget::mouseMoveEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 316
{
c8ae2669 Poul Sander 2026-02-22 17:52 317
    if (m_dragging) {
c8ae2669 Poul Sander 2026-02-22 17:52 318
        m_offset = m_offsetAtDragStart + (event->pos() - m_dragStart);
c8ae2669 Poul Sander 2026-02-22 17:52 319
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 320
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 321
    }
c8ae2669 Poul Sander 2026-02-22 17:52 322
}
c8ae2669 Poul Sander 2026-02-22 17:52 323
c8ae2669 Poul Sander 2026-02-22 17:52 324
void ImageViewWidget::mouseReleaseEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 325
{
c8ae2669 Poul Sander 2026-02-22 17:52 326
    if (event->button() == Qt::LeftButton && m_dragging) {
c8ae2669 Poul Sander 2026-02-22 17:52 327
        m_dragging = false;
c8ae2669 Poul Sander 2026-02-22 17:52 328
        setCursor(Qt::ArrowCursor);
c8ae2669 Poul Sander 2026-02-22 17:52 329
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 330
    }
c8ae2669 Poul Sander 2026-02-22 17:52 331
}
c8ae2669 Poul Sander 2026-02-22 17:52 332
1035a476 Poul Sander 2026-02-23 19:30 333
void ImageViewWidget::mouseDoubleClickEvent(QMouseEvent *event)
1035a476 Poul Sander 2026-02-23 19:30 334
{
1035a476 Poul Sander 2026-02-23 19:30 335
    if (event->button() == Qt::LeftButton) {
1035a476 Poul Sander 2026-02-23 19:30 336
        emit closeRequested();
1035a476 Poul Sander 2026-02-23 19:30 337
        event->accept();
1035a476 Poul Sander 2026-02-23 19:30 338
    }
1035a476 Poul Sander 2026-02-23 19:30 339
}
1035a476 Poul Sander 2026-02-23 19:30 340
c8ae2669 Poul Sander 2026-02-22 17:52 341
void ImageViewWidget::clampOffset(int imgW, int imgH)
c8ae2669 Poul Sander 2026-02-22 17:52 342
{
c8ae2669 Poul Sander 2026-02-22 17:52 343
    // Only allow panning when the drawn image exceeds the widget
c8ae2669 Poul Sander 2026-02-22 17:52 344
    int overflowX = imgW - width();
c8ae2669 Poul Sander 2026-02-22 17:52 345
    int overflowY = imgH - height();
c8ae2669 Poul Sander 2026-02-22 17:52 346
c8ae2669 Poul Sander 2026-02-22 17:52 347
    if (overflowX <= 0)
c8ae2669 Poul Sander 2026-02-22 17:52 348
        m_offset.rx() = 0;
c8ae2669 Poul Sander 2026-02-22 17:52 349
    else {
c8ae2669 Poul Sander 2026-02-22 17:52 350
        int limit = overflowX / 2;
c8ae2669 Poul Sander 2026-02-22 17:52 351
        m_offset.rx() = std::clamp(m_offset.x(), -limit, limit);
c8ae2669 Poul Sander 2026-02-22 17:52 352
    }
c8ae2669 Poul Sander 2026-02-22 17:52 353
c8ae2669 Poul Sander 2026-02-22 17:52 354
    if (overflowY <= 0)
c8ae2669 Poul Sander 2026-02-22 17:52 355
        m_offset.ry() = 0;
c8ae2669 Poul Sander 2026-02-22 17:52 356
    else {
c8ae2669 Poul Sander 2026-02-22 17:52 357
        int limit = overflowY / 2;
c8ae2669 Poul Sander 2026-02-22 17:52 358
        m_offset.ry() = std::clamp(m_offset.y(), -limit, limit);
c8ae2669 Poul Sander 2026-02-22 17:52 359
    }
c8ae2669 Poul Sander 2026-02-22 17:52 360
}
1970-01-01 00:00 361