Lomiri
Loading...
Searching...
No Matches
menucontentactivator.cpp
1/*
2 * Copyright (C) 2013 Canonical Ltd.
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; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Author: Nick Dedekind <nick.dedekind@canonical.com>
17 */
18
19 #include "menucontentactivator.h"
20
21// Essentially a QTimer wrapper
22class ContentTimer : public LomiriIndicators::AbstractTimer
23{
24 Q_OBJECT
25public:
26 ContentTimer(QObject *parent) : LomiriIndicators::AbstractTimer(parent) {
27 m_timer.setSingleShot(false);
28 connect(&m_timer, &QTimer::timeout,
29 this, &LomiriIndicators::AbstractTimer::timeout);
30 }
31 int interval() const override { return m_timer.interval(); }
32 void setInterval(int msecs) override { m_timer.setInterval(msecs); }
33 void start() override { m_timer.start(); LomiriIndicators::AbstractTimer::start(); }
34 void stop() override { m_timer.stop(); LomiriIndicators::AbstractTimer::stop(); }
35private:
36 QTimer m_timer;
37};
38
39class MenuContentActivatorPrivate : public QObject
40{
41 Q_OBJECT
42public:
43 MenuContentActivatorPrivate(MenuContentActivator* parent)
44 : m_running(false),
45 m_baseIndex(0),
46 m_delta(0),
47 m_count(0),
48 m_timer(nullptr),
49 q(parent)
50 {}
51
52 ~MenuContentActivatorPrivate()
53 {
54 qDeleteAll(m_content);
55 m_content.clear();
56 }
57
58 int findNextInactiveDelta(bool* finished = nullptr);
59
60 static int content_count(QQmlListProperty<MenuContentState> *prop);
61 static MenuContentState* content_at(QQmlListProperty<MenuContentState> *prop, int index);
62
63 bool m_running;
64 int m_baseIndex;
65 int m_delta;
66 int m_count;
67 LomiriIndicators::AbstractTimer* m_timer;
68 QMap<int, MenuContentState*> m_content;
69 MenuContentActivator* q;
70};
71
72MenuContentActivator::MenuContentActivator(QObject* parent)
73 : QObject(parent),
74 d(new MenuContentActivatorPrivate(this))
75{
76 qRegisterMetaType<QQmlListProperty<MenuContentState> > ("QQmlListProperty<MenuContentState>");
77
78 setContentTimer(new ContentTimer(this));
79 d->m_timer->setInterval(75);
80}
81
82MenuContentActivator::~MenuContentActivator()
83{
84 delete d;
85}
86
87void MenuContentActivator::restart()
88{
89 // when we start, make sure we have the base index in the list.
90 setMenuContentState(d->m_baseIndex, true);
91 setDelta(0);
92
93 // check if we've finished before starting the timer.
94 bool finished = false;
95 d->findNextInactiveDelta(&finished);
96 if (!finished) {
97 d->m_timer->start();
98 } else {
99 d->m_timer->stop();
100 }
101
102 if (!d->m_running) {
103 d->m_running = true;
104 Q_EMIT runningChanged(true);
105 }
106}
107
108void MenuContentActivator::stop()
109{
110 d->m_timer->stop();
111 if (!d->m_running) {
112 d->m_running = false;
113 Q_EMIT runningChanged(false);
114 }
115}
116
117void MenuContentActivator::clear()
118{
119 qDeleteAll(d->m_content);
120 d->m_content.clear();
121
122 setDelta(0);
123 d->m_timer->stop();
124
125 Q_EMIT contentChanged();
126}
127
128bool MenuContentActivator::isMenuContentActive(int index) const
129{
130 if (d->m_content.contains(index))
131 return d->m_content[index]->isActive();
132 return false;
133}
134
135void MenuContentActivator::setRunning(bool running)
136{
137 if (running) {
138 restart();
139 } else {
140 stop();
141 }
142}
143
144bool MenuContentActivator::isRunning() const
145{
146 return d->m_running;
147}
148
149void MenuContentActivator::setBaseIndex(int index)
150{
151 if (d->m_baseIndex != index) {
152 d->m_baseIndex = index;
153
154 if (isRunning()) {
155 restart();
156 }
157
158 Q_EMIT baseIndexChanged(index);
159 }
160}
161
162int MenuContentActivator::baseIndex() const
163{
164 return d->m_baseIndex;
165}
166
167void MenuContentActivator::setCount(int count)
168{
169 if (d->m_count != count) {
170 d->m_count = count;
171 Q_EMIT countChanged(count);
172
173 if (isRunning()) {
174 restart();
175 }
176 }
177}
178
179int MenuContentActivator::count() const
180{
181 return d->m_count;
182}
183
184void MenuContentActivator::setDelta(int delta)
185{
186 if (d->m_delta != delta) {
187 d->m_delta = delta;
188 Q_EMIT deltaChanged(d->m_delta);
189 }
190}
191
192int MenuContentActivator::delta() const
193{
194 return d->m_delta;
195}
196
197QQmlListProperty<MenuContentState> MenuContentActivator::content()
198{
199 return QQmlListProperty<MenuContentState>(this,
200 0,
201 MenuContentActivatorPrivate::content_count,
202 MenuContentActivatorPrivate::content_at);
203}
204
205void MenuContentActivator::onTimeout()
206{
207 bool finished = false;
208 int tempDelta = d->findNextInactiveDelta(&finished);
209 if (!finished) {
210 setMenuContentState(d->m_baseIndex + tempDelta, true);
211 setDelta(tempDelta);
212 }
213
214 if (finished) {
215 d->m_timer->stop();
216 }
217}
218
219void MenuContentActivator::setContentTimer(LomiriIndicators::AbstractTimer *timer)
220{
221 int interval = 0;
222 bool timerWasRunning = false;
223
224 // can be null when called from the constructor
225 if (d->m_timer) {
226 interval = d->m_timer->interval();
227 timerWasRunning = d->m_timer->isRunning();
228 if (d->m_timer->parent() == this) {
229 delete d->m_timer;
230 }
231 }
232
233 d->m_timer = timer;
234 timer->setInterval(interval);
235 connect(timer, &LomiriIndicators::AbstractTimer::timeout,
236 this, &MenuContentActivator::onTimeout);
237 if (timerWasRunning) {
238 d->m_timer->start();
239 }
240}
241
242void MenuContentActivator::setMenuContentState(int index, bool active)
243{
244 if (d->m_content.contains(index)) {
245 d->m_content[index]->setActive(active);
246 } else {
247 d->m_content[index] = new MenuContentState(active);
248 Q_EMIT contentChanged();
249 }
250}
251
252int MenuContentActivatorPrivate::findNextInactiveDelta(bool* finished)
253{
254 if (m_count == 0 || m_baseIndex >= m_count) {
255 if (finished) *finished = true;
256 return 0;
257 }
258
259 int tmpDelta = m_delta;
260 bool topReached = false, bottomReached = false;
261 while(true) {
262
263 // prechecks for bottom and top limits.
264 if (tmpDelta > 0 && bottomReached) tmpDelta = -tmpDelta;
265 if (tmpDelta < 0 && topReached) tmpDelta = (-tmpDelta) + 1;
266
267 if (tmpDelta > 0) {
268 // negative of baseIndex
269 tmpDelta = -tmpDelta;
270 // reached the bottom?
271 if (m_baseIndex + tmpDelta < 0) {
272 bottomReached = true;
273 // if we've reached the top as well, then we know we're done.
274 if (topReached) {
275 if (finished) *finished = true;
276 return 0;
277 }
278 continue;
279 }
280 } else {
281 // positive of baseIndex
282 tmpDelta = (-tmpDelta) + 1;
283 // reached the top?
284 if (m_baseIndex + tmpDelta >= m_count) {
285 topReached = true;
286 // if we've reached the bottom as well, then we know we're done.
287 if (bottomReached) {
288 if (finished) *finished = true;
289 return 0;
290 }
291 continue;
292 }
293 }
294
295 if (q->isMenuContentActive(m_baseIndex + tmpDelta)) {
296 continue;
297 }
298 break;
299 }
300 if (finished) *finished = false;
301 return tmpDelta;
302}
303
304int MenuContentActivatorPrivate::content_count(QQmlListProperty<MenuContentState> *prop)
305{
306 MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
307 // we'll create MenuContentState on demand.
308 return p->count();
309}
310
311MenuContentState* MenuContentActivatorPrivate::content_at(QQmlListProperty<MenuContentState> *prop, int index)
312{
313 MenuContentActivator *p = qobject_cast<MenuContentActivator*>(prop->object);
314 MenuContentActivatorPrivate *d = p->d;
315
316 if (!d->m_content.contains(index)) {
317 MenuContentState* content = new MenuContentState(false);
318 d->m_content[index] = content;
319 return content;
320 }
321
322 return d->m_content[index];
323}
324
325MenuContentState::MenuContentState(bool active)
326 : m_active(active)
327{
328}
329
330bool MenuContentState::isActive() const
331{
332 return m_active;
333}
334
335void MenuContentState::setActive(bool active)
336{
337 if (m_active != active) {
338 m_active = active;
339 Q_EMIT activeChanged();
340 }
341}
342
343// Because we are defining a new QObject-based class (ContentTimer) here.
344#include "menucontentactivator.moc"