File indexing completed on 2024-05-19 05:35:22
0001 ////////////////////////////////////////////////////////////////////////////// 0002 // oxygentoolbardata.cpp 0003 // stores event filters and maps widgets to timelines for animations 0004 // ------------------- 0005 // 0006 // SPDX-FileCopyrightText: 2009 Hugo Pereira Da Costa <hugo.pereira@free.fr> 0007 // 0008 // SPDX-License-Identifier: MIT 0009 ////////////////////////////////////////////////////////////////////////////// 0010 0011 #include "oxygentoolbardata.h" 0012 0013 #include <QToolButton> 0014 0015 namespace Oxygen 0016 { 0017 //________________________________________________________________________ 0018 ToolBarData::ToolBarData(QObject *parent, QWidget *target, int duration) 0019 : AnimationData(parent, target) 0020 , _opacity(0) 0021 , _progress(0) 0022 , _currentObject(nullptr) 0023 , _entered(false) 0024 { 0025 target->installEventFilter(this); 0026 0027 _animation = new Animation(duration, this); 0028 animation().data()->setDirection(Animation::Forward); 0029 animation().data()->setStartValue(0.0); 0030 animation().data()->setEndValue(1.0); 0031 animation().data()->setTargetObject(this); 0032 animation().data()->setPropertyName("opacity"); 0033 0034 // progress animation 0035 _progressAnimation = new Animation(duration, this); 0036 progressAnimation().data()->setDirection(Animation::Forward); 0037 progressAnimation().data()->setStartValue(0); 0038 progressAnimation().data()->setEndValue(1); 0039 progressAnimation().data()->setTargetObject(this); 0040 progressAnimation().data()->setPropertyName("progress"); 0041 progressAnimation().data()->setEasingCurve(QEasingCurve::Linear); 0042 0043 // add all children widgets to event handler 0044 const auto children = target->children(); 0045 for (QObject *child : children) { 0046 if (qobject_cast<QToolButton *>(child)) 0047 childAddedEvent(child); 0048 } 0049 } 0050 0051 //______________________________________________ 0052 bool ToolBarData::eventFilter(QObject *object, QEvent *event) 0053 { 0054 // check object 0055 const QObject *targetData = target().data(); 0056 if (object == targetData) { 0057 switch (event->type()) { 0058 case QEvent::Enter: { 0059 if (enabled()) { 0060 object->event(event); 0061 enterEvent(object); 0062 return true; 0063 } else 0064 return false; 0065 } 0066 0067 case QEvent::ChildAdded: { 0068 // add children even in disabled case, to make sure they 0069 // are properly registered when engine is enabled 0070 QChildEvent *childEvent(static_cast<QChildEvent *>(event)); 0071 childAddedEvent(childEvent->child()); 0072 break; 0073 } 0074 0075 default: 0076 break; 0077 } 0078 0079 } else if (object->parent() == targetData) { 0080 if (!enabled()) 0081 return false; 0082 0083 switch (event->type()) { 0084 case QEvent::HoverEnter: 0085 childEnterEvent(object); 0086 break; 0087 0088 case QEvent::HoverLeave: 0089 if (currentObject() && !_timer.isActive()) 0090 _timer.start(100, this); 0091 break; 0092 0093 default: 0094 break; 0095 } 0096 } 0097 0098 return false; 0099 } 0100 0101 //____________________________________________________________ 0102 void ToolBarData::updateAnimatedRect(void) 0103 { 0104 // check rect validity 0105 if (currentRect().isNull() || previousRect().isNull()) { 0106 _animatedRect = QRect(); 0107 return; 0108 } 0109 0110 // compute rect located 'between' previous and current 0111 _animatedRect.setLeft(previousRect().left() + progress() * (currentRect().left() - previousRect().left())); 0112 _animatedRect.setRight(previousRect().right() + progress() * (currentRect().right() - previousRect().right())); 0113 _animatedRect.setTop(previousRect().top() + progress() * (currentRect().top() - previousRect().top())); 0114 _animatedRect.setBottom(previousRect().bottom() + progress() * (currentRect().bottom() - previousRect().bottom())); 0115 0116 // trigger update 0117 setDirty(); 0118 return; 0119 } 0120 0121 //________________________________________________________________________ 0122 void ToolBarData::enterEvent(const QObject *) 0123 { 0124 if (_timer.isActive()) 0125 _timer.stop(); 0126 if (animation().data()->isRunning()) 0127 animation().data()->stop(); 0128 if (progressAnimation().data()->isRunning()) 0129 progressAnimation().data()->stop(); 0130 clearPreviousRect(); 0131 clearAnimatedRect(); 0132 0133 return; 0134 } 0135 0136 //________________________________________________________________________ 0137 void ToolBarData::leaveEvent(const QObject *) 0138 { 0139 if (progressAnimation().data()->isRunning()) 0140 progressAnimation().data()->stop(); 0141 if (animation().data()->isRunning()) 0142 animation().data()->stop(); 0143 clearAnimatedRect(); 0144 clearPreviousRect(); 0145 0146 if (currentObject()) { 0147 clearCurrentObject(); 0148 animation().data()->setDirection(Animation::Backward); 0149 animation().data()->start(); 0150 } 0151 0152 return; 0153 } 0154 0155 //________________________________________________________________________ 0156 void ToolBarData::childEnterEvent(const QObject *object) 0157 { 0158 if (object == currentObject()) 0159 return; 0160 0161 const QToolButton *local = qobject_cast<const QToolButton *>(object); 0162 0163 // check if current position match another action 0164 if (local && local->isEnabled()) { 0165 if (_timer.isActive()) 0166 _timer.stop(); 0167 0168 // get rect 0169 QRect activeRect(local->rect().translated(local->mapToParent(QPoint(0, 0)))); 0170 0171 // update previous rect if the current action is valid 0172 if (currentObject()) { 0173 if (!progressAnimation().data()->isRunning()) { 0174 setPreviousRect(currentRect()); 0175 0176 } else if (progress() < 1 && currentRect().isValid() && previousRect().isValid()) { 0177 // re-calculate previous rect so that animatedRect 0178 // is unchanged after currentRect is updated 0179 // this prevents from having jumps in the animation 0180 qreal ratio = progress() / (1.0 - progress()); 0181 _previousRect.adjust(ratio * (currentRect().left() - activeRect.left()), 0182 ratio * (currentRect().top() - activeRect.top()), 0183 ratio * (currentRect().right() - activeRect.right()), 0184 ratio * (currentRect().bottom() - activeRect.bottom())); 0185 } 0186 0187 // update current action 0188 setCurrentObject(local); 0189 setCurrentRect(activeRect); 0190 if (animation().data()->isRunning()) 0191 animation().data()->stop(); 0192 if (!progressAnimation().data()->isRunning()) 0193 progressAnimation().data()->start(); 0194 0195 } else { 0196 setCurrentObject(local); 0197 setCurrentRect(activeRect); 0198 if (!_entered) { 0199 _entered = true; 0200 if (animation().data()->isRunning()) 0201 animation().data()->stop(); 0202 if (!progressAnimation().data()->isRunning()) 0203 progressAnimation().data()->start(); 0204 0205 } else { 0206 setPreviousRect(activeRect); 0207 clearAnimatedRect(); 0208 if (progressAnimation().data()->isRunning()) 0209 progressAnimation().data()->stop(); 0210 animation().data()->setDirection(Animation::Forward); 0211 if (!animation().data()->isRunning()) 0212 animation().data()->start(); 0213 } 0214 } 0215 0216 } else if (currentObject()) { 0217 if (!_timer.isActive()) 0218 _timer.start(100, this); 0219 } 0220 0221 return; 0222 } 0223 0224 //___________________________________________________________________ 0225 void ToolBarData::childAddedEvent(QObject *object) 0226 { 0227 QWidget *widget(qobject_cast<QWidget *>(object)); 0228 if (!widget) 0229 return; 0230 0231 // add connections 0232 connect(animation().data(), SIGNAL(valueChanged(QVariant)), widget, SLOT(update()), Qt::UniqueConnection); 0233 connect(progressAnimation().data(), SIGNAL(valueChanged(QVariant)), widget, SLOT(update()), Qt::UniqueConnection); 0234 0235 // add event filter 0236 widget->removeEventFilter(this); 0237 widget->installEventFilter(this); 0238 } 0239 0240 //___________________________________________________________ 0241 void ToolBarData::timerEvent(QTimerEvent *event) 0242 { 0243 if (event->timerId() != _timer.timerId()) 0244 return AnimationData::timerEvent(event); 0245 _timer.stop(); 0246 leaveEvent(target().data()); 0247 } 0248 }