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;
53fdab93 Poul Sander 2026-05-18 18:45 68
    m_exifData = ExifData{}; // clear stale EXIF until new data is set
58103277 Poul Sander 2026-03-01 22:53 69
58103277 Poul Sander 2026-03-01 22:53 70
    // Check cache first
58103277 Poul Sander 2026-03-01 22:53 71
    if (m_cache.contains(path)) {
58103277 Poul Sander 2026-03-01 22:53 72
        m_pixmap = m_cache[path];
58103277 Poul Sander 2026-03-01 22:53 73
    } else {
58103277 Poul Sander 2026-03-01 22:53 74
        m_pixmap = loadImageFromDisk(path);
58103277 Poul Sander 2026-03-01 22:53 75
        m_cache[path] = m_pixmap;
e1e7f5a6 Poul Sander 2026-02-23 19:40 76
    }
61136b77 Poul Sander 2026-02-20 22:45 77
c58dbdb7 Poul Sander 2026-02-22 17:49 78
    m_zoomMode = FitToScreen;
c58dbdb7 Poul Sander 2026-02-22 17:49 79
    m_zoomFactor = 1.0;
c8ae2669 Poul Sander 2026-02-22 17:52 80
    m_offset = QPoint(0, 0);
61136b77 Poul Sander 2026-02-20 22:45 81
    update();
58103277 Poul Sander 2026-03-01 22:53 82
58103277 Poul Sander 2026-03-01 22:53 83
    // Trigger prefetch of neighbors if they have been set
58103277 Poul Sander 2026-03-01 22:53 84
    if (!m_neighborPaths.isEmpty()) {
58103277 Poul Sander 2026-03-01 22:53 85
        // Evict entries that are no longer in the neighbor window
58103277 Poul Sander 2026-03-01 22:53 86
        QSet<QString> keep(m_neighborPaths.begin(), m_neighborPaths.end());
58103277 Poul Sander 2026-03-01 22:53 87
        keep.insert(m_currentPath);
58103277 Poul Sander 2026-03-01 22:53 88
        for (auto it = m_cache.begin(); it != m_cache.end(); ) {
58103277 Poul Sander 2026-03-01 22:53 89
            if (!keep.contains(it.key()))
58103277 Poul Sander 2026-03-01 22:53 90
                it = m_cache.erase(it);
58103277 Poul Sander 2026-03-01 22:53 91
            else
58103277 Poul Sander 2026-03-01 22:53 92
                ++it;
58103277 Poul Sander 2026-03-01 22:53 93
        }
58103277 Poul Sander 2026-03-01 22:53 94
58103277 Poul Sander 2026-03-01 22:53 95
        // Prefetch neighbors that are not yet cached
58103277 Poul Sander 2026-03-01 22:53 96
        for (const QString &neighbor : m_neighborPaths) {
58103277 Poul Sander 2026-03-01 22:53 97
            prefetchImage(neighbor);
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
58103277 Poul Sander 2026-03-01 22:53 102
void ImageViewWidget::prefetchImage(const QString &path)
58103277 Poul Sander 2026-03-01 22:53 103
{
58103277 Poul Sander 2026-03-01 22:53 104
    if (m_cache.contains(path) || m_pendingLoads.contains(path))
58103277 Poul Sander 2026-03-01 22:53 105
        return;
58103277 Poul Sander 2026-03-01 22:53 106
58103277 Poul Sander 2026-03-01 22:53 107
    m_pendingLoads.insert(path);
58103277 Poul Sander 2026-03-01 22:53 108
    auto *worker = new ImageLoadWorker(path, this);
58103277 Poul Sander 2026-03-01 22:53 109
    connect(worker, &ImageLoadWorker::imageLoaded, this, &ImageViewWidget::onImageLoaded);
58103277 Poul Sander 2026-03-01 22:53 110
    connect(worker, &QThread::finished, worker, &QObject::deleteLater);
58103277 Poul Sander 2026-03-01 22:53 111
    worker->start();
58103277 Poul Sander 2026-03-01 22:53 112
}
58103277 Poul Sander 2026-03-01 22:53 113
58103277 Poul Sander 2026-03-01 22:53 114
void ImageViewWidget::onImageLoaded(const QString &path, const QPixmap &pixmap)
58103277 Poul Sander 2026-03-01 22:53 115
{
58103277 Poul Sander 2026-03-01 22:53 116
    m_pendingLoads.remove(path);
58103277 Poul Sander 2026-03-01 22:53 117
58103277 Poul Sander 2026-03-01 22:53 118
    // Only cache if path is still relevant (current or a neighbor)
58103277 Poul Sander 2026-03-01 22:53 119
    QSet<QString> keep(m_neighborPaths.begin(), m_neighborPaths.end());
58103277 Poul Sander 2026-03-01 22:53 120
    keep.insert(m_currentPath);
58103277 Poul Sander 2026-03-01 22:53 121
    if (keep.contains(path)) {
58103277 Poul Sander 2026-03-01 22:53 122
        m_cache[path] = pixmap;
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
58103277 Poul Sander 2026-03-01 22:53 126
void ImageViewWidget::setNeighborPaths(const QStringList &paths)
58103277 Poul Sander 2026-03-01 22:53 127
{
58103277 Poul Sander 2026-03-01 22:53 128
    m_neighborPaths = paths;
58103277 Poul Sander 2026-03-01 22:53 129
}
58103277 Poul Sander 2026-03-01 22:53 130
58103277 Poul Sander 2026-03-01 22:53 131
void ImageViewWidget::clearCache()
58103277 Poul Sander 2026-03-01 22:53 132
{
58103277 Poul Sander 2026-03-01 22:53 133
    m_cache.clear();
58103277 Poul Sander 2026-03-01 22:53 134
    m_neighborPaths.clear();
61136b77 Poul Sander 2026-02-20 22:45 135
}
61136b77 Poul Sander 2026-02-20 22:45 136
f61bf886 Poul Sander 2026-02-23 19:27 137
void ImageViewWidget::setBackgroundColor(const QString &color)
f61bf886 Poul Sander 2026-02-23 19:27 138
{
f61bf886 Poul Sander 2026-02-23 19:27 139
    m_backgroundColor = color;
f61bf886 Poul Sander 2026-02-23 19:27 140
    QPalette pal = palette();
f61bf886 Poul Sander 2026-02-23 19:27 141
    pal.setColor(QPalette::Window, QColor(color));
f61bf886 Poul Sander 2026-02-23 19:27 142
    setPalette(pal);
f61bf886 Poul Sander 2026-02-23 19:27 143
    update();
f61bf886 Poul Sander 2026-02-23 19:27 144
}
f61bf886 Poul Sander 2026-02-23 19:27 145
61136b77 Poul Sander 2026-02-20 22:45 146
void ImageViewWidget::paintEvent(QPaintEvent *)
61136b77 Poul Sander 2026-02-20 22:45 147
{
61136b77 Poul Sander 2026-02-20 22:45 148
    if (m_pixmap.isNull())
61136b77 Poul Sander 2026-02-20 22:45 149
        return;
61136b77 Poul Sander 2026-02-20 22:45 150
61136b77 Poul Sander 2026-02-20 22:45 151
    QPainter painter(this);
e1e7f5a6 Poul Sander 2026-02-23 19:40 152
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 153
    painter.setRenderHint(QPainter::Antialiasing, true);
e1e7f5a6 Poul Sander 2026-02-23 19:40 154
c58dbdb7 Poul Sander 2026-02-22 17:49 155
    QPixmap drawn;
c58dbdb7 Poul Sander 2026-02-22 17:49 156
c58dbdb7 Poul Sander 2026-02-22 17:49 157
    switch (m_zoomMode) {
c58dbdb7 Poul Sander 2026-02-22 17:49 158
    case FitToScreen:
c58dbdb7 Poul Sander 2026-02-22 17:49 159
        drawn = m_pixmap.scaled(size(), Qt::KeepAspectRatio, Qt::SmoothTransformation);
c58dbdb7 Poul Sander 2026-02-22 17:49 160
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 161
    case OriginalSize:
c58dbdb7 Poul Sander 2026-02-22 17:49 162
        drawn = m_pixmap;
c58dbdb7 Poul Sander 2026-02-22 17:49 163
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 164
    case CustomZoom: {
c58dbdb7 Poul Sander 2026-02-22 17:49 165
        QSize target(static_cast<int>(m_pixmap.width() * m_zoomFactor),
c58dbdb7 Poul Sander 2026-02-22 17:49 166
                     static_cast<int>(m_pixmap.height() * m_zoomFactor));
c58dbdb7 Poul Sander 2026-02-22 17:49 167
        drawn = m_pixmap.scaled(target, Qt::KeepAspectRatio, Qt::SmoothTransformation);
c58dbdb7 Poul Sander 2026-02-22 17:49 168
        break;
c58dbdb7 Poul Sander 2026-02-22 17:49 169
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 170
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 171
c8ae2669 Poul Sander 2026-02-22 17:52 172
    clampOffset(drawn.width(), drawn.height());
c8ae2669 Poul Sander 2026-02-22 17:52 173
c8ae2669 Poul Sander 2026-02-22 17:52 174
    int x = (width()  - drawn.width())  / 2 + m_offset.x();
c8ae2669 Poul Sander 2026-02-22 17:52 175
    int y = (height() - drawn.height()) / 2 + m_offset.y();
c58dbdb7 Poul Sander 2026-02-22 17:49 176
    painter.drawPixmap(x, y, drawn);
53fdab93 Poul Sander 2026-05-18 18:45 177
53fdab93 Poul Sander 2026-05-18 18:45 178
    // EXIF overlay — top-right corner, toggled with 'i'
53fdab93 Poul Sander 2026-05-18 18:45 179
    if (m_showExifOverlay) {
53fdab93 Poul Sander 2026-05-18 18:45 180
        const auto fields = m_exifData.toList();
53fdab93 Poul Sander 2026-05-18 18:45 181
        if (!fields.isEmpty()) {
53fdab93 Poul Sander 2026-05-18 18:45 182
            const int padding = 10;
53fdab93 Poul Sander 2026-05-18 18:45 183
            const int lineH = 18;
53fdab93 Poul Sander 2026-05-18 18:45 184
53fdab93 Poul Sander 2026-05-18 18:45 185
            QFont font = painter.font();
53fdab93 Poul Sander 2026-05-18 18:45 186
            font.setPointSize(9);
53fdab93 Poul Sander 2026-05-18 18:45 187
            painter.setFont(font);
53fdab93 Poul Sander 2026-05-18 18:45 188
            QFontMetrics fm(font);
53fdab93 Poul Sander 2026-05-18 18:45 189
53fdab93 Poul Sander 2026-05-18 18:45 190
            int maxW = 0;
53fdab93 Poul Sander 2026-05-18 18:45 191
            for (const auto &f : fields)
53fdab93 Poul Sander 2026-05-18 18:45 192
                maxW = qMax(maxW, fm.horizontalAdvance(f.first + QLatin1String(": ") + f.second));
53fdab93 Poul Sander 2026-05-18 18:45 193
53fdab93 Poul Sander 2026-05-18 18:45 194
            const int boxW = maxW + padding * 2;
53fdab93 Poul Sander 2026-05-18 18:45 195
            const int boxH = fields.size() * lineH + padding * 2;
53fdab93 Poul Sander 2026-05-18 18:45 196
            const int boxX = width() - boxW - padding;
53fdab93 Poul Sander 2026-05-18 18:45 197
            const int boxY = padding;
53fdab93 Poul Sander 2026-05-18 18:45 198
53fdab93 Poul Sander 2026-05-18 18:45 199
            painter.save();
53fdab93 Poul Sander 2026-05-18 18:45 200
            painter.setPen(Qt::NoPen);
53fdab93 Poul Sander 2026-05-18 18:45 201
            painter.setBrush(QColor(0, 0, 0, 160));
53fdab93 Poul Sander 2026-05-18 18:45 202
            painter.drawRoundedRect(boxX, boxY, boxW, boxH, 8, 8);
53fdab93 Poul Sander 2026-05-18 18:45 203
53fdab93 Poul Sander 2026-05-18 18:45 204
            painter.setPen(Qt::white);
53fdab93 Poul Sander 2026-05-18 18:45 205
            for (int i = 0; i < fields.size(); ++i) {
53fdab93 Poul Sander 2026-05-18 18:45 206
                const QString line = fields[i].first + QLatin1String(": ") + fields[i].second;
53fdab93 Poul Sander 2026-05-18 18:45 207
                painter.drawText(boxX + padding,
53fdab93 Poul Sander 2026-05-18 18:45 208
                                 boxY + padding + fm.ascent() + i * lineH,
53fdab93 Poul Sander 2026-05-18 18:45 209
                                 line);
53fdab93 Poul Sander 2026-05-18 18:45 210
            }
53fdab93 Poul Sander 2026-05-18 18:45 211
            painter.restore();
53fdab93 Poul Sander 2026-05-18 18:45 212
        }
53fdab93 Poul Sander 2026-05-18 18:45 213
    }
61136b77 Poul Sander 2026-02-20 22:45 214
}
61136b77 Poul Sander 2026-02-20 22:45 215
61136b77 Poul Sander 2026-02-20 22:45 216
void ImageViewWidget::keyPressEvent(QKeyEvent *event)
61136b77 Poul Sander 2026-02-20 22:45 217
{
1035a476 Poul Sander 2026-02-23 19:30 218
    if (event->key() == Qt::Key_Escape || event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
61136b77 Poul Sander 2026-02-20 22:45 219
    {
61136b77 Poul Sander 2026-02-20 22:45 220
        emit closeRequested();
61136b77 Poul Sander 2026-02-20 22:45 221
        event->accept();
61136b77 Poul Sander 2026-02-20 22:45 222
        return;
61136b77 Poul Sander 2026-02-20 22:45 223
    }
61136b77 Poul Sander 2026-02-20 22:45 224
1ffc1962 Poul Sander 2026-02-20 23:41 225
    if (event->key() == Qt::Key_PageDown)
1ffc1962 Poul Sander 2026-02-20 23:41 226
    {
1ffc1962 Poul Sander 2026-02-20 23:41 227
        emit nextRequested();
1ffc1962 Poul Sander 2026-02-20 23:41 228
        event->accept();
1ffc1962 Poul Sander 2026-02-20 23:41 229
        return;
1ffc1962 Poul Sander 2026-02-20 23:41 230
    }
1ffc1962 Poul Sander 2026-02-20 23:41 231
1ffc1962 Poul Sander 2026-02-20 23:41 232
    if (event->key() == Qt::Key_PageUp)
1ffc1962 Poul Sander 2026-02-20 23:41 233
    {
1ffc1962 Poul Sander 2026-02-20 23:41 234
        emit previousRequested();
1ffc1962 Poul Sander 2026-02-20 23:41 235
        event->accept();
1ffc1962 Poul Sander 2026-02-20 23:41 236
        return;
1ffc1962 Poul Sander 2026-02-20 23:41 237
    }
1ffc1962 Poul Sander 2026-02-20 23:41 238
c8ae2669 Poul Sander 2026-02-22 17:52 239
    // Arrow keys for panning
c8ae2669 Poul Sander 2026-02-22 17:52 240
    constexpr int panStep = 50;
c8ae2669 Poul Sander 2026-02-22 17:52 241
    if (event->key() == Qt::Key_Left)
c8ae2669 Poul Sander 2026-02-22 17:52 242
    {
c8ae2669 Poul Sander 2026-02-22 17:52 243
        m_offset.rx() += panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 244
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 245
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 246
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 247
    }
c8ae2669 Poul Sander 2026-02-22 17:52 248
    if (event->key() == Qt::Key_Right)
c8ae2669 Poul Sander 2026-02-22 17:52 249
    {
c8ae2669 Poul Sander 2026-02-22 17:52 250
        m_offset.rx() -= panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 251
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 252
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 253
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 254
    }
c8ae2669 Poul Sander 2026-02-22 17:52 255
    if (event->key() == Qt::Key_Up)
c8ae2669 Poul Sander 2026-02-22 17:52 256
    {
c8ae2669 Poul Sander 2026-02-22 17:52 257
        m_offset.ry() += panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 258
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 259
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 260
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 261
    }
c8ae2669 Poul Sander 2026-02-22 17:52 262
    if (event->key() == Qt::Key_Down)
c8ae2669 Poul Sander 2026-02-22 17:52 263
    {
c8ae2669 Poul Sander 2026-02-22 17:52 264
        m_offset.ry() -= panStep;
c8ae2669 Poul Sander 2026-02-22 17:52 265
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 266
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 267
        return;
c8ae2669 Poul Sander 2026-02-22 17:52 268
    }
c8ae2669 Poul Sander 2026-02-22 17:52 269
c58dbdb7 Poul Sander 2026-02-22 17:49 270
    if (event->key() == Qt::Key_Slash)
c58dbdb7 Poul Sander 2026-02-22 17:49 271
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 272
        zoomOriginal();
c58dbdb7 Poul Sander 2026-02-22 17:49 273
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 274
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 275
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 276
c58dbdb7 Poul Sander 2026-02-22 17:49 277
    if (event->key() == Qt::Key_Asterisk)
c58dbdb7 Poul Sander 2026-02-22 17:49 278
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 279
        zoomFitToScreen();
c58dbdb7 Poul Sander 2026-02-22 17:49 280
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 281
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 282
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 283
c58dbdb7 Poul Sander 2026-02-22 17:49 284
    if (event->key() == Qt::Key_Plus)
c58dbdb7 Poul Sander 2026-02-22 17:49 285
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 286
        zoomIn();
c58dbdb7 Poul Sander 2026-02-22 17:49 287
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 288
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 289
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 290
c58dbdb7 Poul Sander 2026-02-22 17:49 291
    if (event->key() == Qt::Key_Minus)
c58dbdb7 Poul Sander 2026-02-22 17:49 292
    {
c58dbdb7 Poul Sander 2026-02-22 17:49 293
        zoomOut();
c58dbdb7 Poul Sander 2026-02-22 17:49 294
        event->accept();
c58dbdb7 Poul Sander 2026-02-22 17:49 295
        return;
c58dbdb7 Poul Sander 2026-02-22 17:49 296
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 297
53fdab93 Poul Sander 2026-05-18 18:45 298
    if (event->key() == Qt::Key_I)
53fdab93 Poul Sander 2026-05-18 18:45 299
    {
53fdab93 Poul Sander 2026-05-18 18:45 300
        toggleExifOverlay();
53fdab93 Poul Sander 2026-05-18 18:45 301
        event->accept();
53fdab93 Poul Sander 2026-05-18 18:45 302
        return;
53fdab93 Poul Sander 2026-05-18 18:45 303
    }
53fdab93 Poul Sander 2026-05-18 18:45 304
61136b77 Poul Sander 2026-02-20 22:45 305
    QWidget::keyPressEvent(event);
61136b77 Poul Sander 2026-02-20 22:45 306
}
c58dbdb7 Poul Sander 2026-02-22 17:49 307
53fdab93 Poul Sander 2026-05-18 18:45 308
void ImageViewWidget::setExifData(const ExifData &data)
53fdab93 Poul Sander 2026-05-18 18:45 309
{
53fdab93 Poul Sander 2026-05-18 18:45 310
    m_exifData = data;
53fdab93 Poul Sander 2026-05-18 18:45 311
    if (m_showExifOverlay)
53fdab93 Poul Sander 2026-05-18 18:45 312
        update();
53fdab93 Poul Sander 2026-05-18 18:45 313
}
53fdab93 Poul Sander 2026-05-18 18:45 314
53fdab93 Poul Sander 2026-05-18 18:45 315
void ImageViewWidget::toggleExifOverlay()
53fdab93 Poul Sander 2026-05-18 18:45 316
{
53fdab93 Poul Sander 2026-05-18 18:45 317
    m_showExifOverlay = !m_showExifOverlay;
53fdab93 Poul Sander 2026-05-18 18:45 318
    update();
53fdab93 Poul Sander 2026-05-18 18:45 319
}
53fdab93 Poul Sander 2026-05-18 18:45 320
c58dbdb7 Poul Sander 2026-02-22 17:49 321
void ImageViewWidget::zoomIn()
c58dbdb7 Poul Sander 2026-02-22 17:49 322
{
c58dbdb7 Poul Sander 2026-02-22 17:49 323
    if (m_zoomMode == FitToScreen) {
c58dbdb7 Poul Sander 2026-02-22 17:49 324
        // Calculate the current effective scale so zooming feels continuous
c58dbdb7 Poul Sander 2026-02-22 17:49 325
        double sx = static_cast<double>(width()) / m_pixmap.width();
c58dbdb7 Poul Sander 2026-02-22 17:49 326
        double sy = static_cast<double>(height()) / m_pixmap.height();
c58dbdb7 Poul Sander 2026-02-22 17:49 327
        m_zoomFactor = std::min(sx, sy);
c58dbdb7 Poul Sander 2026-02-22 17:49 328
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 329
    m_zoomFactor *= 1.25;
c58dbdb7 Poul Sander 2026-02-22 17:49 330
    m_zoomMode = CustomZoom;
c58dbdb7 Poul Sander 2026-02-22 17:49 331
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 332
}
c58dbdb7 Poul Sander 2026-02-22 17:49 333
c58dbdb7 Poul Sander 2026-02-22 17:49 334
void ImageViewWidget::zoomOut()
c58dbdb7 Poul Sander 2026-02-22 17:49 335
{
c58dbdb7 Poul Sander 2026-02-22 17:49 336
    if (m_zoomMode == FitToScreen) {
c58dbdb7 Poul Sander 2026-02-22 17:49 337
        double sx = static_cast<double>(width()) / m_pixmap.width();
c58dbdb7 Poul Sander 2026-02-22 17:49 338
        double sy = static_cast<double>(height()) / m_pixmap.height();
c58dbdb7 Poul Sander 2026-02-22 17:49 339
        m_zoomFactor = std::min(sx, sy);
c58dbdb7 Poul Sander 2026-02-22 17:49 340
    }
c58dbdb7 Poul Sander 2026-02-22 17:49 341
    m_zoomFactor /= 1.25;
c58dbdb7 Poul Sander 2026-02-22 17:49 342
    if (m_zoomFactor < 0.01)
c58dbdb7 Poul Sander 2026-02-22 17:49 343
        m_zoomFactor = 0.01;
c58dbdb7 Poul Sander 2026-02-22 17:49 344
    m_zoomMode = CustomZoom;
c58dbdb7 Poul Sander 2026-02-22 17:49 345
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 346
}
c58dbdb7 Poul Sander 2026-02-22 17:49 347
c58dbdb7 Poul Sander 2026-02-22 17:49 348
void ImageViewWidget::zoomOriginal()
c58dbdb7 Poul Sander 2026-02-22 17:49 349
{
c58dbdb7 Poul Sander 2026-02-22 17:49 350
    m_zoomMode = OriginalSize;
c58dbdb7 Poul Sander 2026-02-22 17:49 351
    m_zoomFactor = 1.0;
c58dbdb7 Poul Sander 2026-02-22 17:49 352
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 353
}
c58dbdb7 Poul Sander 2026-02-22 17:49 354
c58dbdb7 Poul Sander 2026-02-22 17:49 355
void ImageViewWidget::zoomFitToScreen()
c58dbdb7 Poul Sander 2026-02-22 17:49 356
{
c58dbdb7 Poul Sander 2026-02-22 17:49 357
    m_zoomMode = FitToScreen;
c8ae2669 Poul Sander 2026-02-22 17:52 358
    m_offset = QPoint(0, 0);
c58dbdb7 Poul Sander 2026-02-22 17:49 359
    update();
c58dbdb7 Poul Sander 2026-02-22 17:49 360
}
c8ae2669 Poul Sander 2026-02-22 17:52 361
c8ae2669 Poul Sander 2026-02-22 17:52 362
void ImageViewWidget::mousePressEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 363
{
c8ae2669 Poul Sander 2026-02-22 17:52 364
    if (event->button() == Qt::LeftButton) {
c8ae2669 Poul Sander 2026-02-22 17:52 365
        m_dragging = true;
c8ae2669 Poul Sander 2026-02-22 17:52 366
        m_dragStart = event->pos();
c8ae2669 Poul Sander 2026-02-22 17:52 367
        m_offsetAtDragStart = m_offset;
c8ae2669 Poul Sander 2026-02-22 17:52 368
        setCursor(Qt::ClosedHandCursor);
c8ae2669 Poul Sander 2026-02-22 17:52 369
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 370
    }
c8ae2669 Poul Sander 2026-02-22 17:52 371
}
c8ae2669 Poul Sander 2026-02-22 17:52 372
c8ae2669 Poul Sander 2026-02-22 17:52 373
void ImageViewWidget::mouseMoveEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 374
{
c8ae2669 Poul Sander 2026-02-22 17:52 375
    if (m_dragging) {
c8ae2669 Poul Sander 2026-02-22 17:52 376
        m_offset = m_offsetAtDragStart + (event->pos() - m_dragStart);
c8ae2669 Poul Sander 2026-02-22 17:52 377
        update();
c8ae2669 Poul Sander 2026-02-22 17:52 378
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 379
    }
c8ae2669 Poul Sander 2026-02-22 17:52 380
}
c8ae2669 Poul Sander 2026-02-22 17:52 381
c8ae2669 Poul Sander 2026-02-22 17:52 382
void ImageViewWidget::mouseReleaseEvent(QMouseEvent *event)
c8ae2669 Poul Sander 2026-02-22 17:52 383
{
c8ae2669 Poul Sander 2026-02-22 17:52 384
    if (event->button() == Qt::LeftButton && m_dragging) {
c8ae2669 Poul Sander 2026-02-22 17:52 385
        m_dragging = false;
c8ae2669 Poul Sander 2026-02-22 17:52 386
        setCursor(Qt::ArrowCursor);
c8ae2669 Poul Sander 2026-02-22 17:52 387
        event->accept();
c8ae2669 Poul Sander 2026-02-22 17:52 388
    }
c8ae2669 Poul Sander 2026-02-22 17:52 389
}
c8ae2669 Poul Sander 2026-02-22 17:52 390
1035a476 Poul Sander 2026-02-23 19:30 391
void ImageViewWidget::mouseDoubleClickEvent(QMouseEvent *event)
1035a476 Poul Sander 2026-02-23 19:30 392
{
1035a476 Poul Sander 2026-02-23 19:30 393
    if (event->button() == Qt::LeftButton) {
1035a476 Poul Sander 2026-02-23 19:30 394
        emit closeRequested();
1035a476 Poul Sander 2026-02-23 19:30 395
        event->accept();
1035a476 Poul Sander 2026-02-23 19:30 396
    }
1035a476 Poul Sander 2026-02-23 19:30 397
}
1035a476 Poul Sander 2026-02-23 19:30 398
c8ae2669 Poul Sander 2026-02-22 17:52 399
void ImageViewWidget::clampOffset(int imgW, int imgH)
c8ae2669 Poul Sander 2026-02-22 17:52 400
{
c8ae2669 Poul Sander 2026-02-22 17:52 401
    // Only allow panning when the drawn image exceeds the widget
c8ae2669 Poul Sander 2026-02-22 17:52 402
    int overflowX = imgW - width();
c8ae2669 Poul Sander 2026-02-22 17:52 403
    int overflowY = imgH - height();
c8ae2669 Poul Sander 2026-02-22 17:52 404
c8ae2669 Poul Sander 2026-02-22 17:52 405
    if (overflowX <= 0)
c8ae2669 Poul Sander 2026-02-22 17:52 406
        m_offset.rx() = 0;
c8ae2669 Poul Sander 2026-02-22 17:52 407
    else {
c8ae2669 Poul Sander 2026-02-22 17:52 408
        int limit = overflowX / 2;
c8ae2669 Poul Sander 2026-02-22 17:52 409
        m_offset.rx() = std::clamp(m_offset.x(), -limit, limit);
c8ae2669 Poul Sander 2026-02-22 17:52 410
    }
c8ae2669 Poul Sander 2026-02-22 17:52 411
c8ae2669 Poul Sander 2026-02-22 17:52 412
    if (overflowY <= 0)
c8ae2669 Poul Sander 2026-02-22 17:52 413
        m_offset.ry() = 0;
c8ae2669 Poul Sander 2026-02-22 17:52 414
    else {
c8ae2669 Poul Sander 2026-02-22 17:52 415
        int limit = overflowY / 2;
c8ae2669 Poul Sander 2026-02-22 17:52 416
        m_offset.ry() = std::clamp(m_offset.y(), -limit, limit);
c8ae2669 Poul Sander 2026-02-22 17:52 417
    }
c8ae2669 Poul Sander 2026-02-22 17:52 418
}
1970-01-01 00:00 419