File indexing completed on 2024-05-12 16:01:25

0001 /*
0002  *  SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "kis_aspect_ratio_locker.h"
0008 
0009 #include <QSpinBox>
0010 #include <QDoubleSpinBox>
0011 
0012 #include <KoAspectButton.h>
0013 
0014 #include "kis_signals_blocker.h"
0015 #include "kis_assert.h"
0016 #include "kis_debug.h"
0017 #include "kis_slider_spin_box.h"
0018 #include "kis_int_parse_spin_box.h"
0019 #include "kis_double_parse_spin_box.h"
0020 #include "kis_double_parse_unit_spin_box.h"
0021 
0022 
0023 struct SliderWrapper
0024 {
0025     template <class Slider>
0026     SliderWrapper(Slider *slider)
0027         : m_slider(QVariant::fromValue(slider)),
0028           m_object(slider) {}
0029 
0030     void setValue(qreal value) {
0031 
0032         if (m_slider.canConvert<KisDoubleParseUnitSpinBox*>()) {
0033             m_slider.value<KisDoubleParseUnitSpinBox*>()->changeValue(value);
0034 
0035         } else if (m_slider.canConvert<KisDoubleParseSpinBox*>()) {
0036             m_slider.value<KisDoubleParseSpinBox*>()->setValue(value);
0037 
0038         } else if (m_slider.canConvert<KisDoubleSliderSpinBox*>()) {
0039             m_slider.value<KisDoubleSliderSpinBox*>()->setValue(value);
0040 
0041         } else if (m_slider.canConvert<QDoubleSpinBox*>()) {
0042             m_slider.value<QDoubleSpinBox*>()->setValue(value);
0043 
0044         } else if (m_slider.canConvert<KisIntParseSpinBox*>()) {
0045             m_slider.value<KisIntParseSpinBox*>()->setValue(qRound(value));
0046 
0047         } else if (m_slider.canConvert<KisSliderSpinBox*>()) {
0048             m_slider.value<KisSliderSpinBox*>()->setValue(qRound(value));
0049 
0050         } else if (m_slider.canConvert<QSpinBox*>()) {
0051             m_slider.value<QSpinBox*>()->setValue(qRound(value));
0052         }
0053     }
0054 
0055     qreal value() const {
0056         qreal result = 0.0;
0057 
0058         if (m_slider.canConvert<KisDoubleParseUnitSpinBox*>()) {
0059             result = m_slider.value<KisDoubleParseUnitSpinBox*>()->value();
0060 
0061         } else if (m_slider.canConvert<KisDoubleParseSpinBox*>()) {
0062             result = m_slider.value<KisDoubleParseSpinBox*>()->value();
0063 
0064         } else if (m_slider.canConvert<KisDoubleSliderSpinBox*>()) {
0065             result = m_slider.value<KisDoubleSliderSpinBox*>()->value();
0066 
0067         } else if (m_slider.canConvert<QDoubleSpinBox*>()) {
0068             result = m_slider.value<QDoubleSpinBox*>()->value();
0069 
0070         } else if (m_slider.canConvert<KisIntParseSpinBox*>()) {
0071             result = m_slider.value<KisIntParseSpinBox*>()->value();
0072 
0073         } else if (m_slider.canConvert<KisSliderSpinBox*>()) {
0074             result = m_slider.value<KisSliderSpinBox*>()->value();
0075 
0076         } else if (m_slider.canConvert<QSpinBox*>()) {
0077             result = m_slider.value<QSpinBox*>()->value();
0078 
0079         }
0080 
0081         return result;
0082     }
0083 
0084     bool isDragging() const {
0085         bool result = false;
0086 
0087         if (m_slider.canConvert<KisSliderSpinBox*>()) {
0088             result = m_slider.value<KisSliderSpinBox*>()->isDragging();
0089 
0090         } else if (m_slider.canConvert<KisDoubleSliderSpinBox*>()) {
0091             result = m_slider.value<KisDoubleSliderSpinBox*>()->isDragging();
0092         }
0093 
0094         return result;
0095     }
0096 
0097     void connectDraggingFinished(QObject *receiver, const char *amember) {
0098 
0099         if (m_slider.canConvert<KisSliderSpinBox*>()) {
0100             QObject::connect(m_slider.value<KisSliderSpinBox*>(), SIGNAL(draggingFinished()),
0101                              receiver, amember);
0102 
0103         } else if (m_slider.canConvert<KisDoubleSliderSpinBox*>()) {
0104             QObject::connect(m_slider.value<KisDoubleSliderSpinBox*>(), SIGNAL(draggingFinished()),
0105                              receiver, amember);
0106         }
0107     }
0108 
0109     QObject* object() const {
0110         return m_object;
0111     }
0112 
0113 private:
0114     QVariant m_slider;
0115     QObject *m_object;
0116 };
0117 
0118 struct KisAspectRatioLocker::Private
0119 {
0120     QScopedPointer<SliderWrapper> spinOne;
0121     QScopedPointer<SliderWrapper> spinTwo;
0122     KoAspectButton *aspectButton = 0;
0123 
0124     qreal aspectRatio = 1.0;
0125     bool blockUpdatesOnDrag = false;
0126 };
0127 
0128 
0129 KisAspectRatioLocker::KisAspectRatioLocker(QObject *parent)
0130     : QObject(parent),
0131       m_d(new Private)
0132 {
0133 }
0134 
0135 KisAspectRatioLocker::~KisAspectRatioLocker()
0136 {
0137 }
0138 
0139 template <class SpinBoxType>
0140 void KisAspectRatioLocker::connectSpinBoxes(SpinBoxType *spinOne, SpinBoxType *spinTwo, KoAspectButton *aspectButton)
0141 {
0142     m_d->spinOne.reset(new SliderWrapper(spinOne));
0143     m_d->spinTwo.reset(new SliderWrapper(spinTwo));
0144     m_d->aspectButton = aspectButton;
0145 
0146     if (QVariant::fromValue(spinOne->value()).type() == QVariant::Double) {
0147         connect(spinOne, SIGNAL(valueChanged(qreal)), SLOT(slotSpinOneChanged()));
0148         connect(spinTwo, SIGNAL(valueChanged(qreal)), SLOT(slotSpinTwoChanged()));
0149     } else {
0150         connect(spinOne, SIGNAL(valueChanged(int)), SLOT(slotSpinOneChanged()));
0151         connect(spinTwo, SIGNAL(valueChanged(int)), SLOT(slotSpinTwoChanged()));
0152     }
0153 
0154     m_d->spinOne->connectDraggingFinished(this, SLOT(slotSpinDraggingFinished()));
0155     m_d->spinTwo->connectDraggingFinished(this, SLOT(slotSpinDraggingFinished()));
0156 
0157     connect(m_d->aspectButton, SIGNAL(keepAspectRatioChanged(bool)), SLOT(slotAspectButtonChanged()));
0158     slotAspectButtonChanged();
0159 }
0160 
0161 template KRITAUI_EXPORT void KisAspectRatioLocker::connectSpinBoxes(QSpinBox *spinOne, QSpinBox *spinTwo, KoAspectButton *aspectButton);
0162 template KRITAUI_EXPORT void KisAspectRatioLocker::connectSpinBoxes(QDoubleSpinBox *spinOne, QDoubleSpinBox *spinTwo, KoAspectButton *aspectButton);
0163 template KRITAUI_EXPORT void KisAspectRatioLocker::connectSpinBoxes(KisSliderSpinBox *spinOne, KisSliderSpinBox *spinTwo, KoAspectButton *aspectButton);
0164 template KRITAUI_EXPORT void KisAspectRatioLocker::connectSpinBoxes(KisDoubleSliderSpinBox *spinOne, KisDoubleSliderSpinBox *spinTwo, KoAspectButton *aspectButton);
0165 template KRITAUI_EXPORT void KisAspectRatioLocker::connectSpinBoxes(KisIntParseSpinBox *spinOne, KisIntParseSpinBox *spinTwo, KoAspectButton *aspectButton);
0166 template KRITAUI_EXPORT void KisAspectRatioLocker::connectSpinBoxes(KisDoubleParseSpinBox *spinOne, KisDoubleParseSpinBox *spinTwo, KoAspectButton *aspectButton);
0167 template KRITAUI_EXPORT void KisAspectRatioLocker::connectSpinBoxes(KisDoubleParseUnitSpinBox *spinOne, KisDoubleParseUnitSpinBox *spinTwo, KoAspectButton *aspectButton);
0168 
0169 void KisAspectRatioLocker::slotSpinOneChanged()
0170 {
0171     if (m_d->aspectButton->keepAspectRatio()) {
0172         KisSignalsBlocker b(m_d->spinTwo->object());
0173         m_d->spinTwo->setValue(m_d->aspectRatio * m_d->spinOne->value());
0174     }
0175 
0176     if (!m_d->blockUpdatesOnDrag || !m_d->spinOne->isDragging()) {
0177         emit sliderValueChanged();
0178     }
0179 }
0180 
0181 void KisAspectRatioLocker::slotSpinTwoChanged()
0182 {
0183     if (m_d->aspectButton->keepAspectRatio()) {
0184         KisSignalsBlocker b(m_d->spinOne->object());
0185         m_d->spinOne->setValue(m_d->spinTwo->value() / m_d->aspectRatio);
0186     }
0187 
0188     if (!m_d->blockUpdatesOnDrag || !m_d->spinTwo->isDragging()) {
0189         emit sliderValueChanged();
0190     }
0191 }
0192 
0193 void KisAspectRatioLocker::slotAspectButtonChanged()
0194 {
0195     if (m_d->aspectButton->keepAspectRatio() &&
0196         m_d->spinTwo->value() > 0 &&
0197         m_d->spinOne->value() > 0) {
0198 
0199         m_d->aspectRatio = qreal(m_d->spinTwo->value()) / m_d->spinOne->value();
0200     } else {
0201         m_d->aspectRatio = 1.0;
0202     }
0203 
0204     if (!m_d->spinTwo->isDragging()) {
0205         emit aspectButtonChanged();
0206         emit aspectButtonToggled(m_d->aspectButton->keepAspectRatio());
0207     }
0208 }
0209 
0210 void KisAspectRatioLocker::slotSpinDraggingFinished()
0211 {
0212     if (m_d->blockUpdatesOnDrag) {
0213         emit sliderValueChanged();
0214     }
0215 }
0216 
0217 void KisAspectRatioLocker::setBlockUpdateSignalOnDrag(bool value)
0218 {
0219     m_d->blockUpdatesOnDrag = value;
0220 }
0221 
0222 void KisAspectRatioLocker::updateAspect()
0223 {
0224     KisSignalsBlocker b(this);
0225     slotAspectButtonChanged();
0226 }