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"