File indexing completed on 2024-05-19 05:35:25
0001 // krazy:excludeall=qclasses 0002 0003 ////////////////////////////////////////////////////////////////////////////// 0004 // oxygenlineeditdata.cpp 0005 // data container for QLineEdit transition 0006 // ------------------- 0007 // 0008 // SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0009 // 0010 // SPDX-License-Identifier: MIT 0011 ////////////////////////////////////////////////////////////////////////////// 0012 0013 #include "oxygenlineeditdata.h" 0014 0015 #include <QDateTimeEdit> 0016 #include <QDoubleSpinBox> 0017 #include <QEvent> 0018 #include <QPainter> 0019 #include <QSpinBox> 0020 #include <QStyle> 0021 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 0022 #include <QStyleOptionFrameV2> 0023 #else 0024 #include <QStyleOptionFrame> 0025 #endif 0026 0027 namespace Oxygen 0028 { 0029 // use 20 milliseconds for animation lock 0030 const int LineEditData::_lockTime = 20; 0031 0032 //______________________________________________________ 0033 LineEditData::LineEditData(QObject *parent, QLineEdit *target, int duration) 0034 : TransitionData(parent, target, duration) 0035 , _target(target) 0036 , _hasClearButton(false) 0037 , _edited(false) 0038 { 0039 _target.data()->installEventFilter(this); 0040 0041 checkClearButton(); 0042 0043 connect(_target.data(), SIGNAL(destroyed()), SLOT(targetDestroyed())); 0044 connect(_target.data(), SIGNAL(textEdited(QString)), SLOT(textEdited())); 0045 connect(_target.data(), SIGNAL(textChanged(QString)), SLOT(textChanged())); 0046 0047 /* 0048 Additional signal/slot connections depending on widget's parent. 0049 This is needed because parents sometime disable the textChanged signal of the embedded 0050 QLineEdit 0051 */ 0052 if (auto spinbox = qobject_cast<QSpinBox *>(_target.data()->parentWidget())) { 0053 connect(spinbox, &QSpinBox::textChanged, this, &LineEditData::textChanged); 0054 } else if (auto spinbox = qobject_cast<QDoubleSpinBox *>(_target.data()->parentWidget())) { 0055 connect(spinbox, &QDoubleSpinBox::textChanged, this, &LineEditData::textChanged); 0056 } else if (qobject_cast<QDateTimeEdit *>(_target.data()->parentWidget())) { 0057 connect(_target.data()->parentWidget(), SIGNAL(dateTimeChanged(QDateTime)), SLOT(textChanged())); 0058 } 0059 0060 // update cached pixmap on selection change 0061 connect(_target.data(), SIGNAL(selectionChanged()), SLOT(selectionChanged())); 0062 } 0063 0064 //___________________________________________________________________ 0065 bool LineEditData::eventFilter(QObject *object, QEvent *event) 0066 { 0067 if (!(enabled() && object && object == _target.data())) { 0068 return TransitionData::eventFilter(object, event); 0069 } 0070 0071 switch (event->type()) { 0072 case QEvent::Show: 0073 case QEvent::Resize: 0074 case QEvent::Move: 0075 transition().data()->setEndPixmap(QPixmap()); 0076 break; 0077 0078 default: 0079 break; 0080 } 0081 0082 return TransitionData::eventFilter(object, event); 0083 } 0084 0085 //___________________________________________________________________ 0086 void LineEditData::timerEvent(QTimerEvent *event) 0087 { 0088 if (event->timerId() == _timer.timerId()) { 0089 _timer.stop(); 0090 checkClearButton(); 0091 if (enabled() && transition() && _target && _target.data()->isVisible()) { 0092 setRecursiveCheck(true); 0093 transition().data()->setEndPixmap(transition().data()->grab(_target.data(), targetRect())); 0094 setRecursiveCheck(false); 0095 } 0096 0097 } else if (event->timerId() == _animationLockTimer.timerId()) { 0098 unlockAnimations(); 0099 0100 } else 0101 return TransitionData::timerEvent(event); 0102 } 0103 0104 //___________________________________________________________________ 0105 void LineEditData::checkClearButton(void) 0106 { 0107 if (!_target) 0108 return; 0109 const QObjectList children = _target.data()->children(); 0110 _hasClearButton = false; 0111 for (QObject *child : children) { 0112 if (child->inherits("KLineEditButton")) { 0113 _hasClearButton = true; 0114 _clearButtonRect = static_cast<QWidget *>(child)->geometry(); 0115 break; 0116 } 0117 } 0118 0119 return; 0120 } 0121 0122 //___________________________________________________________________ 0123 void LineEditData::textEdited(void) 0124 { 0125 _edited = true; 0126 if (!recursiveCheck()) { 0127 _timer.start(0, this); 0128 } 0129 } 0130 0131 //___________________________________________________________________ 0132 void LineEditData::selectionChanged(void) 0133 { 0134 if (!recursiveCheck()) { 0135 _timer.start(0, this); 0136 } 0137 } 0138 0139 //___________________________________________________________________ 0140 void LineEditData::textChanged(void) 0141 { 0142 // check whether text change was triggered manually 0143 // in which case do not start transition 0144 if (_edited) { 0145 _edited = false; 0146 return; 0147 } 0148 0149 if (transition().data()->isAnimated()) { 0150 transition().data()->endAnimation(); 0151 } 0152 0153 if (isLocked()) { 0154 // if locked one do not start the new animation, to prevent flicker 0155 // instead, one hides the transition pixmap, trigger an update, and return. 0156 // animations are re-locked. 0157 transition().data()->hide(); 0158 lockAnimations(); 0159 _timer.start(0, this); 0160 return; 0161 } 0162 0163 if (initializeAnimation()) { 0164 lockAnimations(); 0165 animate(); 0166 0167 } else { 0168 transition().data()->hide(); 0169 } 0170 } 0171 0172 //___________________________________________________________________ 0173 bool LineEditData::initializeAnimation(void) 0174 { 0175 if (!(enabled() && _target && _target.data()->isVisible())) 0176 return false; 0177 0178 if (recursiveCheck()) 0179 return false; 0180 0181 QRect current(targetRect()); 0182 0183 transition().data()->setOpacity(0); 0184 transition().data()->setGeometry(current); 0185 0186 if (_widgetRect.isValid() && !transition().data()->currentPixmap().isNull() && _widgetRect != current) { 0187 // if label geometry has changed since last animation 0188 // one must clone the pixmap to make it match the right 0189 // geometry before starting the animation. 0190 QPixmap pixmap(current.size()); 0191 pixmap.fill(Qt::transparent); 0192 QPainter p(&pixmap); 0193 p.drawPixmap(_widgetRect.topLeft() - current.topLeft(), transition().data()->currentPixmap()); 0194 p.end(); 0195 transition().data()->setStartPixmap(pixmap); 0196 0197 } else { 0198 transition().data()->setStartPixmap(transition().data()->currentPixmap()); 0199 } 0200 0201 bool valid(!transition().data()->startPixmap().isNull()); 0202 if (valid) { 0203 transition().data()->show(); 0204 transition().data()->raise(); 0205 } 0206 0207 setRecursiveCheck(true); 0208 transition().data()->setEndPixmap(transition().data()->grab(_target.data(), targetRect())); 0209 setRecursiveCheck(false); 0210 0211 return valid; 0212 } 0213 0214 //___________________________________________________________________ 0215 bool LineEditData::animate(void) 0216 { 0217 transition().data()->animate(); 0218 return true; 0219 } 0220 0221 //___________________________________________________________________ 0222 void LineEditData::targetDestroyed(void) 0223 { 0224 setEnabled(false); 0225 _target.clear(); 0226 } 0227 }