]> cloud.milkyroute.net Git - dolphin.git/blob - src/kitemviews/private/kitemlistsmoothscroller.cpp
dolphin: convert kitemviews/ to qt5 signal slot syntax
[dolphin.git] / src / kitemviews / private / kitemlistsmoothscroller.cpp
1 /***************************************************************************
2 * Copyright (C) 2011 by Peter Penz <peter.penz19@gmail.com> *
3 * *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
8 * *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
13 * *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
19
20 #include "kitemlistsmoothscroller.h"
21
22 #include <KGlobalSettings>
23 #include <QEvent>
24 #include <QPropertyAnimation>
25 #include <QScrollBar>
26 #include <QWheelEvent>
27
28 #include <KDebug>
29
30 KItemListSmoothScroller::KItemListSmoothScroller(QScrollBar* scrollBar,
31 QObject* parent) :
32 QObject(parent),
33 m_scrollBarPressed(false),
34 m_smoothScrolling(true),
35 m_scrollBar(scrollBar),
36 m_animation(0)
37 {
38 m_animation = new QPropertyAnimation(this);
39 const int duration = (KGlobalSettings::graphicEffectsLevel() == KGlobalSettings::NoEffects) ? 1 : 100;
40 m_animation->setDuration(duration);
41 connect(m_animation, &QPropertyAnimation::stateChanged,
42 this, &KItemListSmoothScroller::slotAnimationStateChanged);
43
44 m_scrollBar->installEventFilter(this);
45 }
46
47 KItemListSmoothScroller::~KItemListSmoothScroller()
48 {
49 }
50
51 void KItemListSmoothScroller::setScrollBar(QScrollBar *scrollBar)
52 {
53 m_scrollBar = scrollBar;
54 }
55
56 QScrollBar* KItemListSmoothScroller::scrollBar() const
57 {
58 return m_scrollBar;
59 }
60
61 void KItemListSmoothScroller::setTargetObject(QObject* target)
62 {
63 m_animation->setTargetObject(target);
64 }
65
66 QObject* KItemListSmoothScroller::targetObject() const
67 {
68 return m_animation->targetObject();
69 }
70
71 void KItemListSmoothScroller::setPropertyName(const QByteArray& propertyName)
72 {
73 m_animation->setPropertyName(propertyName);
74 }
75
76 QByteArray KItemListSmoothScroller::propertyName() const
77 {
78 return m_animation->propertyName();
79 }
80
81 void KItemListSmoothScroller::scrollContentsBy(qreal distance)
82 {
83 QObject* target = targetObject();
84 if (!target) {
85 return;
86 }
87
88 const QByteArray name = propertyName();
89 const qreal currentOffset = target->property(name).toReal();
90 if (static_cast<int>(currentOffset) == m_scrollBar->value()) {
91 // The current offset is already synchronous to the scrollbar
92 return;
93 }
94
95 const bool animRunning = (m_animation->state() == QAbstractAnimation::Running);
96 if (animRunning) {
97 // Stopping a running animation means skipping the range from the current offset
98 // until the target offset. To prevent skipping of the range the difference
99 // is added to the new target offset.
100 const qreal oldEndOffset = m_animation->endValue().toReal();
101 distance += (currentOffset - oldEndOffset);
102 }
103
104 const qreal endOffset = currentOffset - distance;
105 if (m_smoothScrolling || animRunning) {
106 qreal startOffset = currentOffset;
107 if (animRunning) {
108 // If the animation was running and has been interrupted by assigning a new end-offset
109 // one frame must be added to the start-offset to keep the animation smooth. This also
110 // assures that animation proceeds even in cases where new end-offset are triggered
111 // within a very short timeslots.
112 startOffset += (endOffset - currentOffset) * 1000 / (m_animation->duration() * 60);
113 if (currentOffset < endOffset) {
114 startOffset = qMin(startOffset, endOffset);
115 } else {
116 startOffset = qMax(startOffset, endOffset);
117 }
118 }
119
120 m_animation->stop();
121 m_animation->setStartValue(startOffset);
122 m_animation->setEndValue(endOffset);
123 m_animation->setEasingCurve(animRunning ? QEasingCurve::OutQuad : QEasingCurve::InOutQuad);
124 m_animation->start();
125 target->setProperty(name, startOffset);
126 } else {
127 target->setProperty(name, endOffset);
128 }
129 }
130
131 void KItemListSmoothScroller::scrollTo(qreal position)
132 {
133 int newValue = position;
134 newValue = qBound(0, newValue, m_scrollBar->maximum());
135
136 if (newValue != m_scrollBar->value()) {
137 m_smoothScrolling = true;
138 m_scrollBar->setValue(newValue);
139 }
140 }
141
142 bool KItemListSmoothScroller::requestScrollBarUpdate(int newMaximum)
143 {
144 if (m_animation->state() == QAbstractAnimation::Running) {
145 if (newMaximum == m_scrollBar->maximum()) {
146 // The value has been changed by the animation, no update
147 // of the scrollbars is required as their target state will be
148 // reached with the end of the animation.
149 return false;
150 }
151
152 // The maximum has been changed which indicates that the content
153 // of the view has been changed. Stop the animation in any case and
154 // update the scrollbars immediately.
155 m_animation->stop();
156 }
157 return true;
158 }
159
160 bool KItemListSmoothScroller::eventFilter(QObject* obj, QEvent* event)
161 {
162 Q_ASSERT(obj == m_scrollBar);
163
164 switch (event->type()) {
165 case QEvent::MouseButtonPress:
166 m_scrollBarPressed = true;
167 m_smoothScrolling = true;
168 break;
169
170 case QEvent::MouseButtonRelease:
171 m_scrollBarPressed = false;
172 m_smoothScrolling = false;
173 break;
174
175 case QEvent::Wheel:
176 handleWheelEvent(static_cast<QWheelEvent*>(event));
177 break;
178
179 default:
180 break;
181 }
182
183 return QObject::eventFilter(obj, event);
184 }
185
186 void KItemListSmoothScroller::slotAnimationStateChanged(QAbstractAnimation::State newState,
187 QAbstractAnimation::State oldState)
188 {
189 Q_UNUSED(oldState);
190 if (newState == QAbstractAnimation::Stopped && m_smoothScrolling && !m_scrollBarPressed) {
191 m_smoothScrolling = false;
192 }
193 }
194
195 void KItemListSmoothScroller::handleWheelEvent(QWheelEvent* event)
196 {
197 const int numDegrees = event->delta() / 8;
198 const int numSteps = numDegrees / 15;
199
200 const bool previous = m_smoothScrolling;
201
202 m_smoothScrolling = true;
203 const int value = m_scrollBar->value();
204 const int pageStep = m_scrollBar->pageStep();
205 m_scrollBar->setValue(value - numSteps * pageStep);
206
207 m_smoothScrolling = previous;
208
209 event->accept();
210 }
211
212 #include "kitemlistsmoothscroller.moc"