File indexing completed on 2024-05-05 05:53:45

0001 /*
0002     This source file is part of Konsole, a terminal emulator.
0003 
0004     SPDX-FileCopyrightText: 2007-2008 Robert Knight <robertknight@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 // Own
0010 #include "ColorSchemeWallpaper.h"
0011 
0012 // Konsole
0013 #include "ColorScheme.h"
0014 
0015 // Qt
0016 #include <QImage>
0017 #include <QImageReader>
0018 #include <QMovie>
0019 #include <QPainter>
0020 
0021 using namespace Konsole;
0022 
0023 ColorSchemeWallpaper::ColorSchemeWallpaper(const QString &path,
0024                                            const ColorSchemeWallpaper::FillStyle style,
0025                                            const QPointF &anchor,
0026                                            const qreal &opacity,
0027                                            const ColorSchemeWallpaper::FlipType flipType)
0028     : _path(path)
0029     , _picture(nullptr)
0030     , _movie(nullptr)
0031     , _style(style)
0032     , _anchor(anchor)
0033     , _opacity(opacity)
0034     , _flipType(flipType)
0035     , _isAnimated(false)
0036     , _frameDelay(17) // Approx. 60FPS
0037 {
0038     float x = _anchor.x(), y = _anchor.y();
0039 
0040     if (x < 0 || x > 1.0f || y < 0 || y > 1.0f)
0041         _anchor = QPointF(0.5, 0.5);
0042 }
0043 
0044 ColorSchemeWallpaper::~ColorSchemeWallpaper() = default;
0045 
0046 void ColorSchemeWallpaper::load()
0047 {
0048     if (_path.isEmpty()) {
0049         return;
0050     }
0051 
0052     QImageReader reader(_path);
0053     _isAnimated = reader.supportsAnimation();
0054     if (_isAnimated) {
0055         if (_movie == nullptr) {
0056             _movie = std::make_unique<QMovie>();
0057         }
0058 
0059         if (!_movie->isValid()) {
0060             _movie->setFileName(_path);
0061             _movie->start();
0062         }
0063 
0064         // Initialize _picture in load, to avoid null checking for both _picture and _movie in draw.
0065         if (_picture == nullptr) {
0066             _picture = std::make_unique<QPixmap>();
0067         }
0068 
0069         if (_picture->isNull()) {
0070             const QImage image = _movie->currentImage();
0071             const QImage transformed = FlipImage(image, _flipType);
0072             _picture->convertFromImage(transformed);
0073         }
0074     } else {
0075         // Cleanup animated image
0076         if (_movie != nullptr) {
0077             if (_movie->isValid()) {
0078                 _movie->stop();
0079             }
0080             _movie.reset();
0081         }
0082 
0083         // Create and load original pixmap
0084         if (_picture == nullptr) {
0085             _picture = std::make_unique<QPixmap>();
0086         }
0087 
0088         if (_picture->isNull()) {
0089             const QImage image(_path);
0090             const QImage transformed = FlipImage(image, _flipType);
0091             _picture->convertFromImage(transformed);
0092         }
0093     }
0094 }
0095 
0096 bool ColorSchemeWallpaper::isNull() const
0097 {
0098     return _path.isEmpty();
0099 }
0100 
0101 bool ColorSchemeWallpaper::draw(QPainter &painter, const QRect rect, qreal bgColorOpacity, const QColor &backgroundColor)
0102 {
0103     if ((_picture == nullptr) || _picture->isNull()) {
0104         return false;
0105     }
0106 
0107     painter.save();
0108     painter.setCompositionMode(QPainter::CompositionMode_SourceOver);
0109     painter.setOpacity(bgColorOpacity);
0110     painter.fillRect(rect, backgroundColor);
0111     painter.setOpacity(_opacity);
0112 
0113     if (_isAnimated) {
0114         if (_movie->state() == QMovie::NotRunning) {
0115             _movie->start();
0116         }
0117         if (_picture != nullptr) {
0118             _picture.reset();
0119         }
0120         if (_picture == nullptr) {
0121             _picture = std::make_unique<QPixmap>();
0122         }
0123         if (_picture->isNull()) {
0124             QImage currentImage = _movie->currentImage();
0125             const QImage transformed = FlipImage(currentImage, _flipType);
0126             _picture->convertFromImage(transformed);
0127         }
0128     }
0129     if (_style == Tile) {
0130         painter.drawTiledPixmap(rect, *_picture, rect.topLeft());
0131     } else {
0132         QRectF srcRect = ScaledRect(painter.viewport().size(), _picture->size(), rect);
0133         painter.drawPixmap(rect, *_picture, srcRect);
0134     }
0135 
0136     painter.restore();
0137 
0138     return true;
0139 }
0140 
0141 QString ColorSchemeWallpaper::path() const
0142 {
0143     return _path;
0144 }
0145 
0146 ColorSchemeWallpaper::FillStyle ColorSchemeWallpaper::style() const
0147 {
0148     return _style;
0149 }
0150 
0151 ColorSchemeWallpaper::FlipType ColorSchemeWallpaper::flipType() const
0152 {
0153     return _flipType;
0154 }
0155 
0156 QPointF ColorSchemeWallpaper::anchor() const
0157 {
0158     return _anchor;
0159 }
0160 
0161 qreal ColorSchemeWallpaper::opacity() const
0162 {
0163     return _opacity;
0164 }
0165 
0166 QRectF ColorSchemeWallpaper::ScaledRect(const QSize viewportSize, const QSize pictureSize, const QRect rect)
0167 {
0168     QRectF scaledRect = QRectF();
0169     QSize scaledSize = _style == NoScaling ? pictureSize : pictureSize.scaled(viewportSize, RatioMode());
0170 
0171     double scaleX = pictureSize.width() / static_cast<double>(scaledSize.width());
0172     double scaleY = pictureSize.height() / static_cast<double>(scaledSize.height());
0173 
0174     double offsetX = (scaledSize.width() - viewportSize.width()) * _anchor.x();
0175     double offsetY = (scaledSize.height() - viewportSize.height()) * _anchor.y();
0176 
0177     scaledRect.setX((rect.x() + offsetX) * scaleX);
0178     scaledRect.setY((rect.y() + offsetY) * scaleY);
0179 
0180     scaledRect.setWidth(rect.width() * scaleX);
0181     scaledRect.setHeight(rect.height() * scaleY);
0182 
0183     return scaledRect;
0184 }
0185 
0186 Qt::AspectRatioMode ColorSchemeWallpaper::RatioMode()
0187 {
0188     switch (_style) {
0189     case Crop:
0190         return Qt::KeepAspectRatioByExpanding;
0191     case Adapt:
0192         return Qt::KeepAspectRatio;
0193     case Tile:
0194     case Stretch:
0195     default:
0196         return Qt::IgnoreAspectRatio;
0197     }
0198 }
0199 
0200 QImage ColorSchemeWallpaper::FlipImage(const QImage image, const ColorSchemeWallpaper::FlipType flipType)
0201 {
0202     switch (flipType) {
0203     case Horizontal:
0204         return image.mirrored(true, false);
0205     case Vertical:
0206         return image.mirrored(false, true);
0207     case Both:
0208         return image.mirrored(true, true);
0209     default:
0210         return image;
0211     }
0212 }
0213 
0214 bool ColorSchemeWallpaper::isAnimated() const
0215 {
0216     return _isAnimated;
0217 }
0218 
0219 int ColorSchemeWallpaper::getFrameDelay() const
0220 {
0221     return _frameDelay;
0222 }
0223 
0224 #include "moc_ColorSchemeWallpaper.cpp"