File indexing completed on 2024-05-19 04:26:42

0001 /*
0002  *  SPDX-FileCopyrightText: 2022 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "KisImageResolutionProxy.h"
0008 
0009 #include <kis_image.h>
0010 #include "kis_pointer_utils.h"
0011 #include "kis_signal_auto_connection.h"
0012 
0013 namespace {
0014 
0015 struct IdentityResolutionProxyHolder
0016 {
0017     IdentityResolutionProxyHolder()
0018         : identity(new KisImageResolutionProxy())
0019     {
0020     }
0021 
0022     KisImageResolutionProxySP identity;
0023 };
0024 
0025 Q_GLOBAL_STATIC(IdentityResolutionProxyHolder, s_holder)
0026 }
0027 
0028 struct KisImageResolutionProxy::Private {
0029     Private(KisImageWSP image)
0030         : lastKnownXRes(1.0),
0031           lastKnownYRes(1.0)
0032     {
0033         setImage(image);
0034     }
0035 
0036     Private(const Private &rhs)
0037         : lastKnownXRes(rhs.lastKnownXRes),
0038           lastKnownYRes(rhs.lastKnownYRes)
0039     {
0040         setImage(rhs.image);
0041     }
0042 
0043     ~Private() {
0044         /**
0045          * Since we are not using QObject for the connection,
0046          * we should disconnect the connection automatically
0047          * on destruction.
0048          */
0049         if (imageConnection) {
0050             QObject::disconnect(imageConnection);
0051         }
0052     }
0053 
0054     KisImageWSP image;
0055     qreal lastKnownXRes;
0056     qreal lastKnownYRes;
0057     QMetaObject::Connection imageConnection;
0058 
0059     void setImage(KisImageWSP image);
0060     void slotImageResolutionChanged(qreal xRes, qreal yRes);
0061 };
0062 
0063 KisImageResolutionProxy::KisImageResolutionProxy()
0064     : KisImageResolutionProxy(nullptr)
0065 {
0066 }
0067 
0068 KisImageResolutionProxy::KisImageResolutionProxy(KisImageWSP image)
0069     : m_d(new Private(image))
0070 {
0071 }
0072 
0073 KisImageResolutionProxy::KisImageResolutionProxy(const KisImageResolutionProxy &rhs)
0074     : QObject(nullptr)
0075     , m_d(new Private(*rhs.m_d))
0076 {
0077 }
0078 
0079 KisImageResolutionProxy::~KisImageResolutionProxy()
0080 {
0081 }
0082 
0083 qreal KisImageResolutionProxy::xRes() const
0084 {
0085     return m_d->image ? m_d->image->xRes() : m_d->lastKnownXRes;
0086 }
0087 
0088 qreal KisImageResolutionProxy::yRes() const
0089 {
0090     return m_d->image ? m_d->image->yRes() : m_d->lastKnownYRes;
0091 }
0092 
0093 bool KisImageResolutionProxy::compareResolution(const KisImageResolutionProxy &rhs) const
0094 {
0095     return qFuzzyCompare(xRes(), rhs.xRes()) &&
0096         qFuzzyCompare(yRes(), rhs.yRes());
0097 
0098 }
0099 
0100 KisImageResolutionProxySP KisImageResolutionProxy::cloneDetached() const
0101 {
0102     KisImageResolutionProxySP proxy(new KisImageResolutionProxy(*this));
0103     proxy->m_d->setImage(nullptr);
0104     return proxy;
0105 }
0106 
0107 KisImageResolutionProxySP KisImageResolutionProxy::createOrCloneDetached(KisImageWSP image) const
0108 {
0109     return image ? toQShared(new KisImageResolutionProxy(image)) : cloneDetached();
0110 }
0111 
0112 KisImageResolutionProxySP KisImageResolutionProxy::identity()
0113 {
0114     return s_holder->identity;
0115 }
0116 
0117 void KisImageResolutionProxy::Private::slotImageResolutionChanged(qreal xRes, qreal yRes)
0118 {
0119     lastKnownXRes = xRes;
0120     lastKnownYRes = yRes;
0121 }
0122 
0123 void KisImageResolutionProxy::Private::setImage(KisImageWSP image)
0124 {
0125     QObject::disconnect(imageConnection);
0126 
0127     if (image) {
0128         /**
0129          * NOTE: we cannot just use detached converter all the
0130          * time, because we cannot update its values in time
0131          * before the next update after image changed its
0132          * resolution (the signal is emitted at the very end
0133          * of the operation).
0134          */
0135 
0136         this->image = image;
0137         lastKnownXRes = image->xRes();
0138         lastKnownYRes = image->yRes();
0139 
0140         imageConnection = connect(image.data(), &KisImage::sigResolutionChanged,
0141                                     std::bind(&Private::slotImageResolutionChanged, this,
0142                                               std::placeholders::_1, std::placeholders::_2));
0143     } else {
0144         /**
0145          * The layer will keep "the lastly used resolution"
0146          * until being attached to the new image.
0147          */
0148         this->image = nullptr;
0149     }
0150 }