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 }