File indexing completed on 2025-03-09 03:52:10

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2014-09-18
0007  * Description : slideshow image widget
0008  *
0009  * SPDX-FileCopyrightText: 2014-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  * SPDX-FileCopyrightText: 2019-2020 by Minh Nghia Duong <minhnghiaduong997 at gmail dot com>
0011  *
0012  * SPDX-License-Identifier: GPL-2.0-or-later
0013  *
0014  * ============================================================ */
0015 
0016 #include "slideimage.h"
0017 
0018 // Qt includes
0019 
0020 #include <QApplication>
0021 #include <QPainter>
0022 #include <QScreen>
0023 #include <QWindow>
0024 
0025 // Local includes
0026 
0027 #include "digikam_debug.h"
0028 #include "previewloadthread.h"
0029 
0030 using namespace Digikam;
0031 
0032 namespace DigikamGenericSlideShowPlugin
0033 {
0034 
0035 class Q_DECL_HIDDEN SlideImage::Private
0036 {
0037 
0038 public:
0039 
0040     explicit Private()
0041       : previewThread       (nullptr),
0042         previewPreloadThread(nullptr)
0043     {
0044     }
0045 
0046     PreviewSettings     previewSettings;
0047 
0048     QPixmap             pixmap;
0049 
0050     QUrl                currentImage;
0051 
0052     DImg                preview;
0053     PreviewLoadThread*  previewThread;
0054     PreviewLoadThread*  previewPreloadThread;
0055 };
0056 
0057 SlideImage::SlideImage(QWidget* const parent)
0058     : QWidget(parent),
0059       d      (new Private)
0060 {
0061     setAttribute(Qt::WA_OpaquePaintEvent);
0062     setWindowFlags(Qt::FramelessWindowHint);
0063     setMouseTracking(true);
0064 
0065     d->previewThread        = new PreviewLoadThread();
0066     d->previewPreloadThread = new PreviewLoadThread();
0067 
0068     connect(d->previewThread, SIGNAL(signalImageLoaded(LoadingDescription,DImg)),
0069             this, SLOT(slotGotImagePreview(LoadingDescription,DImg)));
0070 }
0071 
0072 SlideImage::~SlideImage()
0073 {
0074     d->previewPreloadThread->stopAllTasks();
0075     d->previewThread->stopAllTasks();
0076 
0077     d->previewPreloadThread->wait();
0078     d->previewThread->wait();
0079 
0080     delete d->previewPreloadThread;
0081     delete d->previewThread;
0082     delete d;
0083 }
0084 
0085 void SlideImage::setPreviewSettings(const PreviewSettings& settings)
0086 {
0087     d->previewSettings = settings;
0088 }
0089 
0090 void SlideImage::setLoadUrl(const QUrl& url)
0091 {
0092     d->currentImage = url;
0093 
0094     // calculate preview size which is used for fast previews
0095 
0096     QScreen* screen = qApp->primaryScreen();
0097 
0098     if (QWidget* const widget = nativeParentWidget())
0099     {
0100         if (QWindow* const window = widget->windowHandle())
0101         {
0102             screen = window->screen();
0103         }
0104     }
0105 
0106     QSize desktopSize = screen->geometry().size();
0107     int deskSize      = qMax(640, qMax(desktopSize.height(), desktopSize.width()));
0108     d->previewThread->load(url.toLocalFile(), d->previewSettings, deskSize);
0109 }
0110 
0111 void SlideImage::setPreloadUrl(const QUrl& url)
0112 {
0113     // calculate preview size which is used for fast previews
0114 
0115     QScreen* screen = qApp->primaryScreen();
0116 
0117     if (QWidget* const widget = nativeParentWidget())
0118     {
0119         if (QWindow* const window = widget->windowHandle())
0120         {
0121             screen = window->screen();
0122         }
0123     }
0124 
0125     QSize desktopSize = screen->geometry().size();
0126     int deskSize      = qMax(640, qMax(desktopSize.height(), desktopSize.width()));
0127     d->previewPreloadThread->load(url.toLocalFile(), d->previewSettings, deskSize);
0128 }
0129 
0130 void SlideImage::paintEvent(QPaintEvent*)
0131 {
0132     QPainter p(this);
0133     p.drawPixmap(0, 0, width(), height(), d->pixmap,
0134                  0, 0, d->pixmap.width(), d->pixmap.height());
0135     p.end();
0136 }
0137 
0138 void SlideImage::slotGotImagePreview(const LoadingDescription& desc, const DImg& preview)
0139 {
0140     if ((desc.filePath != d->currentImage.toLocalFile()) || desc.isThumbnail())
0141     {
0142         return;
0143     }
0144 
0145     d->preview.reset();
0146 
0147     if (!DImg::isAnimatedImage(desc.filePath))      // Special case for animated images as GIF or NMG
0148     {
0149         d->preview = preview;
0150     }
0151 
0152     if (!d->preview.isNull())
0153     {
0154         updatePixmap();
0155         update();
0156 
0157         Q_EMIT signalImageLoaded(true);
0158 
0159         return;
0160     }
0161 
0162     Q_EMIT signalImageLoaded(false);
0163 }
0164 
0165 void SlideImage::updatePixmap()
0166 {
0167     /**
0168      * For high resolution ("retina") displays, Mac OS X / Qt
0169      * report only half of the physical resolution in terms of
0170      * pixels, i.e. every logical pixels corresponds to 2x2
0171      * physical pixels. However, UI elements and fonts are
0172      * nevertheless rendered at full resolution, and pixmaps
0173      * as well, provided their resolution is high enough (that
0174      * is, higher than the reported, logical resolution).
0175      *
0176      * To work around this, we render the photos not a logical
0177      * resolution, but with the photo's full resolution, but
0178      * at the screen's aspect ratio. When we later draw this
0179      * high resolution bitmap, it is up to Qt to scale the
0180      * photo to the true physical resolution.  The ratio
0181      * computed below is the ratio between the photo and
0182      * screen resolutions, or equivalently the factor by which
0183      * we need to increase the pixel size of the rendered
0184      * pixmap.
0185      */
0186 
0187     double dpr     = devicePixelRatio();
0188 
0189     QSize fullSize = QSizeF(dpr * width(), dpr * height()).toSize();
0190     d->pixmap      = QPixmap(fullSize);
0191     d->pixmap.fill(Qt::black);
0192     QPainter p(&(d->pixmap));
0193 
0194     QPixmap pix(d->preview.smoothScale(d->pixmap.width(),
0195                                        d->pixmap.height(),
0196                                        Qt::KeepAspectRatio).convertToPixmap());
0197 
0198     p.drawPixmap((d->pixmap.width()  - pix.width())  / 2,
0199                  (d->pixmap.height() - pix.height()) / 2, pix,
0200                  0, 0, pix.width(), pix.height());
0201 }
0202 
0203 } // namespace DigikamGenericSlideShowPlugin
0204 
0205 #include "moc_slideimage.cpp"