1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
5 **
6 ** This file is part of the demonstration applications of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file. Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "menumanager.h"
43 #include "colors.h"
44 #include "menucontent.h"
45 #include "examplecontent.h"
46
47 MenuManager *MenuManager::pInstance = 0;
48
instance()49 MenuManager * MenuManager::instance()
50 {
51 if (!MenuManager::pInstance)
52 MenuManager::pInstance = new MenuManager();
53 return MenuManager::pInstance;
54 }
55
MenuManager()56 MenuManager::MenuManager()
57 {
58 this->ticker = 0;
59 this->tickerInAnim = 0;
60 this->upButton = 0;
61 this->downButton = 0;
62 this->helpEngine = 0;
63 this->score = new Score();
64 this->currentMenu = QLatin1String("[no menu visible]");
65 this->currentCategory = QLatin1String("[no category visible]");
66 this->currentMenuButtons = QLatin1String("[no menu buttons visible]");
67 this->currentInfo = QLatin1String("[no info visible]");
68 this->currentMenuCode = -1;
69 this->readXmlDocument();
70 this->initHelpEngine();
71 }
72
~MenuManager()73 MenuManager::~MenuManager()
74 {
75 delete this->score;
76 delete this->contentsDoc;
77 delete this->helpEngine;
78 }
79
getResource(const QString & name)80 QByteArray MenuManager::getResource(const QString &name)
81 {
82 QByteArray ba = this->helpEngine->fileData(name);
83 if (Colors::verbose && ba.isEmpty())
84 qDebug() << " - WARNING: Could not get " << name;
85 return ba;
86 }
87
readXmlDocument()88 void MenuManager::readXmlDocument()
89 {
90 this->contentsDoc = new QDomDocument();
91 QString errorStr;
92 int errorLine;
93 int errorColumn;
94
95 QFile file(":/xml/examples.xml");
96 bool statusOK = this->contentsDoc->setContent(&file, true, &errorStr, &errorLine, &errorColumn);
97 if (!statusOK){
98 QMessageBox::critical(0,
99 QObject::tr("DOM Parser"),
100 QObject::tr("Could not read or find the contents document. Error at line %1, column %2:\n%3")
101 .arg(errorLine).arg(errorColumn).arg(errorStr)
102 );
103 exit(-1);
104 }
105 }
106
initHelpEngine()107 void MenuManager::initHelpEngine()
108 {
109 this->helpRootUrl = QString("qthelp://com.trolltech.qt.%1%2%3/qdoc/")
110 .arg(QT_VERSION >> 16).arg((QT_VERSION >> 8) & 0xFF)
111 .arg(QT_VERSION & 0xFF);
112
113 // Store help collection file in cache dir of assistant
114 QString cacheDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation)
115 + QLatin1String("/Trolltech/Assistant/");
116 QString helpDataFile = QString(QLatin1String("qtdemo_%1.qhc")).arg(QLatin1String(QT_VERSION_STR));
117
118 QDir dir;
119 if (!dir.exists(cacheDir))
120 dir.mkpath(cacheDir);
121
122 // Create help engine (and new
123 // helpDataFile if it does not exist):
124 this->helpEngine = new QHelpEngineCore(cacheDir + helpDataFile);
125 this->helpEngine->setupData();
126
127 QString qtDocRoot = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/qch");
128 qtDocRoot = QDir(qtDocRoot).absolutePath();
129
130 QStringList qchFiles;
131 qchFiles << QLatin1String("/qt.qch")
132 << QLatin1String("/designer.qch")
133 << QLatin1String("/linguist.qch");
134
135 QString oldDir = helpEngine->customValue(QLatin1String("docDir"), QString()).toString();
136 if (oldDir != qtDocRoot) {
137 foreach (const QString &qchFile, qchFiles)
138 helpEngine->unregisterDocumentation(QHelpEngineCore::namespaceName(qtDocRoot + qchFile));
139 }
140
141 // If the data that the engine will work
142 // on is not yet registered, do it now:
143 foreach (const QString &qchFile, qchFiles)
144 helpEngine->registerDocumentation(qtDocRoot + qchFile);
145
146 helpEngine->setCustomValue(QLatin1String("docDir"), qtDocRoot);
147 }
148
itemSelected(int userCode,const QString & menuName)149 void MenuManager::itemSelected(int userCode, const QString &menuName)
150 {
151 switch (userCode){
152 case LAUNCH:
153 this->launchExample(this->currentInfo);
154 break;
155 case LAUNCH_QML:
156 this->launchQmlExample(this->currentInfo);
157 break;
158 case DOCUMENTATION:
159 this->showDocInAssistant(this->currentInfo);
160 break;
161 case QUIT:
162 this->window->loop = false;
163 QCoreApplication::quit();
164 break;
165 case FULLSCREEN:
166 this->window->toggleFullscreen();
167 break;
168 case ROOT:
169 // out:
170 this->score->queueMovie(this->currentMenu + " -out", Score::FROM_START, Score::LOCK_ITEMS);
171 this->score->queueMovie(this->currentMenuButtons + " -out", Score::FROM_START, Score::LOCK_ITEMS);
172 this->score->queueMovie(this->currentInfo + " -out");
173 this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
174 this->score->queueMovie("back -out", Score::ONLY_IF_VISIBLE);
175 if(qmlRoot)
176 qmlRoot->setProperty("show", QVariant(false));
177 // book-keeping:
178 this->currentMenuCode = ROOT;
179 this->currentMenu = menuName + " -menu1";
180 this->currentMenuButtons = menuName + " -buttons";
181 this->currentInfo = menuName + " -info";
182 // in:
183 this->score->queueMovie("upndown -shake");
184 this->score->queueMovie(this->currentMenu, Score::FROM_START, Score::UNLOCK_ITEMS);
185 this->score->queueMovie(this->currentMenuButtons, Score::FROM_START, Score::UNLOCK_ITEMS);
186 this->score->queueMovie(this->currentInfo);
187 if (!Colors::noTicker){
188 this->ticker->doIntroTransitions = true;
189 this->tickerInAnim->startDelay = 2000;
190 this->ticker->useGuideQt();
191 this->score->queueMovie("ticker", Score::NEW_ANIMATION_ONLY);
192 }
193 break;
194 case MENU1:
195 // out:
196 this->score->queueMovie(this->currentMenu + " -out", Score::FROM_START, Score::LOCK_ITEMS);
197 this->score->queueMovie(this->currentMenuButtons + " -out", Score::FROM_START, Score::LOCK_ITEMS);
198 this->score->queueMovie(this->currentInfo + " -out");
199 if(qmlRoot)
200 qmlRoot->setProperty("show", QVariant(false));
201 // book-keeping:
202 this->currentMenuCode = MENU1;
203 this->currentCategory = menuName;
204 this->currentMenu = menuName + " -menu1";
205 this->currentInfo = menuName + " -info";
206 // in:
207 this->score->queueMovie("upndown -shake");
208 this->score->queueMovie("back -in");
209 this->score->queueMovie(this->currentMenu, Score::FROM_START, Score::UNLOCK_ITEMS);
210 this->score->queueMovie(this->currentInfo);
211 if (!Colors::noTicker)
212 this->ticker->useGuideTt();
213 break;
214 case MENU2:
215 // out:
216 this->score->queueMovie(this->currentInfo + " -out", Score::NEW_ANIMATION_ONLY);
217 this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
218 if(qmlRoot)
219 qmlRoot->setProperty("show", QVariant(false));
220 // book-keeping:
221 this->currentMenuCode = MENU2;
222 this->currentInfo = menuName;
223 // in / shake:
224 this->score->queueMovie("upndown -shake");
225 this->score->queueMovie("back -shake");
226 this->score->queueMovie(this->currentMenu + " -shake");
227 this->score->queueMovie(this->currentInfo, Score::NEW_ANIMATION_ONLY);
228 this->score->queueMovie(this->currentInfo + " -buttons", Score::NEW_ANIMATION_ONLY);
229 if (!Colors::noTicker){
230 this->score->queueMovie("ticker -out", Score::NEW_ANIMATION_ONLY);
231 }
232 break;
233 case UP:{
234 QString backMenu = this->info[this->currentMenu]["back"];
235 if (!backMenu.isNull()){
236 this->score->queueMovie(this->currentMenu + " -top_out", Score::FROM_START, Score::LOCK_ITEMS);
237 this->score->queueMovie(backMenu + " -bottom_in", Score::FROM_START, Score::UNLOCK_ITEMS);
238 this->currentMenu = backMenu;
239 }
240 break; }
241 case DOWN:{
242 QString moreMenu = this->info[this->currentMenu]["more"];
243 if (!moreMenu.isNull()){
244 this->score->queueMovie(this->currentMenu + " -bottom_out", Score::FROM_START, Score::LOCK_ITEMS);
245 this->score->queueMovie(moreMenu + " -top_in", Score::FROM_START, Score::UNLOCK_ITEMS);
246 this->currentMenu = moreMenu;
247 }
248 break; }
249 case BACK:{
250 if (this->currentMenuCode == MENU2){
251 // out:
252 this->score->queueMovie(this->currentInfo + " -out", Score::NEW_ANIMATION_ONLY);
253 this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
254 if(qmlRoot)
255 qmlRoot->setProperty("show", QVariant(false));
256 // book-keeping:
257 this->currentMenuCode = MENU1;
258 this->currentMenuButtons = this->currentCategory + " -buttons";
259 this->currentInfo = this->currentCategory + " -info";
260 // in / shake:
261 this->score->queueMovie("upndown -shake");
262 this->score->queueMovie(this->currentMenu + " -shake");
263 this->score->queueMovie(this->currentInfo, Score::NEW_ANIMATION_ONLY);
264 this->score->queueMovie(this->currentInfo + " -buttons", Score::NEW_ANIMATION_ONLY);
265 if (!Colors::noTicker){
266 this->ticker->doIntroTransitions = false;
267 this->tickerInAnim->startDelay = 500;
268 this->score->queueMovie("ticker", Score::NEW_ANIMATION_ONLY);
269 }
270 } else if (this->currentMenuCode != ROOT)
271 itemSelected(ROOT, Colors::rootMenuName);
272 break; }
273 }
274
275 // update back- and more buttons
276 bool noBackMenu = this->info[this->currentMenu]["back"].isNull();
277 bool noMoreMenu = this->info[this->currentMenu]["more"].isNull();
278 this->upButton->setState(noBackMenu ? TextButton::DISABLED : TextButton::OFF);
279 this->downButton->setState(noMoreMenu ? TextButton::DISABLED : TextButton::OFF);
280
281 if (this->score->hasQueuedMovies()){
282 this->score->playQue();
283 // Playing new movies might include
284 // loading etc. So ignore the FPS
285 // at this point
286 this->window->fpsHistory.clear();
287 }
288 }
289
showDocInAssistant(const QString & name)290 void MenuManager::showDocInAssistant(const QString &name)
291 {
292 QString url = this->resolveDocUrl(name);
293 if (Colors::verbose)
294 qDebug() << "Sending URL to Assistant:" << url;
295
296 // Start assistant if it's not already running:
297 if (this->assistantProcess.state() != QProcess::Running){
298 QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator();
299 #if !defined(Q_OS_MAC)
300 app += QLatin1String("assistant");
301 #else
302 app += QLatin1String("Assistant.app/Contents/MacOS/Assistant");
303 #endif
304 QStringList args;
305 args << QLatin1String("-enableRemoteControl");
306 this->assistantProcess.start(app, args);
307 if (!this->assistantProcess.waitForStarted()) {
308 QMessageBox::critical(0, tr("Qt Demo"), tr("Could not start Qt Assistant.").arg(app));
309 return;
310 }
311 }
312
313 // Send command through remote control even if the process
314 // was started to activate assistant and bring it to front:
315 QTextStream str(&this->assistantProcess);
316 str << "SetSource " << url << QLatin1Char('\n') << endl;
317 }
318
launchExample(const QString & name)319 void MenuManager::launchExample(const QString &name)
320 {
321 QString executable = this->resolveExeFile(name);
322 #ifdef Q_OS_MAC
323 if (Colors::verbose)
324 qDebug() << "Launching:" << executable;
325 bool success = QDesktopServices::openUrl(QUrl::fromLocalFile(executable));
326 if (!success){
327 QMessageBox::critical(0, tr("Failed to launch the example"),
328 tr("Could not launch the example. Ensure that it has been built."),
329 QMessageBox::Cancel);
330 }
331 #else // Not mac. To not break anything regarding dll's etc, keep it the way it was before:
332 QProcess *process = new QProcess(this);
333 connect(process, SIGNAL(finished(int)), this, SLOT(exampleFinished()));
334 connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(exampleError(QProcess::ProcessError)));
335
336 #ifdef Q_OS_WIN
337 //make sure it finds the dlls on windows
338 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
339 env.insert(QLatin1String("PATH"), QLibraryInfo::location(QLibraryInfo::BinariesPath)
340 + QLatin1Char(';') + env.value(QLatin1String("Path")));
341 process->setProcessEnvironment(env);
342 #endif
343
344 if (info[name]["changedirectory"] != "false"){
345 QString workingDirectory = resolveDataDir(name);
346 process->setWorkingDirectory(workingDirectory);
347 if (Colors::verbose)
348 qDebug() << "Setting working directory:" << workingDirectory;
349 }
350
351 if (Colors::verbose)
352 qDebug() << "Launching:" << executable;
353 process->start(executable);
354 #endif
355 }
356
launchQmlExample(const QString & name)357 void MenuManager::launchQmlExample(const QString &name)
358 {
359 #ifndef QT_NO_DECLARATIVE
360 if(!qmlRoot){
361 exampleError(QProcess::UnknownError);
362 return;
363 }
364 //resolveQmlFilename - refactor to separate fn?
365 QString dirName = this->info[name]["dirname"];
366 QString category = this->info[name]["category"];
367 QString fileName = this->info[name]["filename"];
368 QDir dir;
369 if (category == "demos")
370 dir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
371 else
372 dir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
373 QFile file(dir.path() + "/" + dirName + "/" + fileName + "/" + "main.qml");
374 if(!file.exists()){
375 //try dirname.qml as well
376 file.setFileName(dir.path() + "/" + dirName + "/" + fileName + "/" + fileName.split('/').last() + ".qml");
377 if(!file.exists()){
378 exampleError(QProcess::UnknownError);
379 return;
380 }
381 }
382
383 qmlRoot->setProperty("qmlFile", QVariant(""));//unload component
384 qmlRoot->setProperty("show", QVariant(true));
385 qmlRoot->setProperty("qmlFile", QUrl::fromLocalFile(file.fileName()));
386 #else
387 exampleError(QProcess::UnknownError);
388 #endif
389 }
390
quitQML()391 void MenuManager::quitQML()
392 {
393 if(qmlRoot)
394 qmlRoot->setProperty("show", QVariant(false));
395 }
396
exampleFinished()397 void MenuManager::exampleFinished()
398 {
399 }
400
exampleError(QProcess::ProcessError error)401 void MenuManager::exampleError(QProcess::ProcessError error)
402 {
403 if (error != QProcess::Crashed)
404 QMessageBox::critical(0, tr("Failed to launch the example"),
405 tr("Could not launch the example. Ensure that it has been built."),
406 QMessageBox::Cancel);
407 }
408
init(MainWindow * window)409 void MenuManager::init(MainWindow *window)
410 {
411 this->window = window;
412
413 // Create div:
414 this->createTicker();
415 this->createUpnDownButtons();
416 this->createBackButton();
417
418 // Create first level menu:
419 QDomElement rootElement = this->contentsDoc->documentElement();
420 this->createRootMenu(rootElement);
421
422 // Create second level menus:
423 QDomNode level2MenuNode = rootElement.firstChild();
424 while (!level2MenuNode.isNull()){
425 QDomElement level2MenuElement = level2MenuNode.toElement();
426 this->createSubMenu(level2MenuElement);
427
428 // create leaf menu and example info:
429 QDomNode exampleNode = level2MenuElement.firstChild();
430 while (!exampleNode.isNull()){
431 QDomElement exampleElement = exampleNode.toElement();
432 this->readInfoAboutExample(exampleElement);
433 this->createLeafMenu(exampleElement);
434 exampleNode = exampleNode.nextSibling();
435 }
436
437 level2MenuNode = level2MenuNode.nextSibling();
438 }
439
440 qmlRoot = 0;
441 #ifndef QT_NO_DECLARATIVE
442 // Create QML Loader
443 declarativeEngine = new QDeclarativeEngine(this);
444 connect(declarativeEngine, SIGNAL(quit()),
445 this, SLOT(quitQML()));
446
447 QDeclarativeComponent component(declarativeEngine, QUrl("qrc:qml/qmlShell.qml"), this);
448 QDeclarativeItem* qmlRootItem = 0;
449 if(component.isReady()){
450 qmlRoot = component.create();
451 qmlRootItem = qobject_cast<QDeclarativeItem*>(qmlRoot);
452 }else{
453 qDebug() << component.status() << component.errorString();
454 }
455
456 if(qmlRootItem){
457 qmlRootItem->setHeight(this->window->scene->sceneRect().height());
458 qmlRootItem->setWidth(this->window->scene->sceneRect().width());
459 qmlRootItem->setZValue(101);//Above other items
460 qmlRootItem->setCursor(Qt::ArrowCursor);
461 window->scene->addItem(qmlRootItem);
462
463 //Note that QML adds key handling to the app.
464 window->viewport()->setFocusPolicy(Qt::NoFocus);//Correct keyboard focus handling
465 window->setFocusPolicy(Qt::StrongFocus);
466 window->scene->setStickyFocus(true);
467 window->setFocus();
468 }else{
469 qDebug() << "Error initializing QML subsystem, Declarative examples will not work";
470 }
471 #endif
472 }
473
readInfoAboutExample(const QDomElement & example)474 void MenuManager::readInfoAboutExample(const QDomElement &example)
475 {
476 QString name = example.attribute("name");
477 if (this->info.contains(name))
478 qWarning() << "__WARNING: MenuManager::readInfoAboutExample: Demo/example with name"
479 << name << "appears twice in the xml-file!__";
480
481 this->info[name]["filename"] = example.attribute("filename");
482 this->info[name]["category"] = example.parentNode().toElement().tagName();
483 this->info[name]["dirname"] = example.parentNode().toElement().attribute("dirname");
484 this->info[name]["changedirectory"] = example.attribute("changedirectory");
485 this->info[name]["image"] = example.attribute("image");
486 this->info[name]["qml"] = example.attribute("qml");
487 }
488
resolveDataDir(const QString & name)489 QString MenuManager::resolveDataDir(const QString &name)
490 {
491 QString dirName = this->info[name]["dirname"];
492 QString category = this->info[name]["category"];
493 QString fileName = this->info[name]["filename"];
494
495 QDir dir;
496 if (category == "demos")
497 dir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
498 else
499 dir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
500
501 dir.cd(dirName);
502 dir.cd(fileName);
503 return dir.absolutePath();
504 }
505
resolveExeFile(const QString & name)506 QString MenuManager::resolveExeFile(const QString &name)
507 {
508 QString dirName = this->info[name]["dirname"];
509 QString category = this->info[name]["category"];
510 QString fileName = this->info[name]["filename"];
511
512 QDir dir;
513 if (category == "demos")
514 dir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
515 else
516 dir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
517
518 dir.cd(dirName);
519 dir.cd(fileName);
520
521 fileName = fileName.split(QLatin1Char('/')).last();
522 #ifdef Q_OS_WIN
523 fileName += QLatin1String(".exe");
524 #endif
525 // UNIX, Mac non-framework and Windows installed builds.
526 const QFile installedFile(dir.path() + QLatin1Char('/') + fileName);
527 if (installedFile.exists())
528 return installedFile.fileName();
529 // Windows in-source builds
530 #if defined(Q_OS_WIN)
531 const QFile winR(dir.path() + QLatin1String("/release/") + fileName);
532 if (winR.exists())
533 return winR.fileName();
534 const QFile winD(dir.path() + QLatin1String("/debug/") + fileName);
535 if (winD.exists())
536 return winD.fileName();
537 #elif defined(Q_OS_MAC)
538 // Mac frameworks
539 const QFile mac(dir.path() + QLatin1Char('/') + fileName + QLatin1String(".app"));
540 if (mac.exists())
541 return mac.fileName();
542 #endif
543 if (Colors::verbose)
544 qDebug() << "- WARNING: Could not resolve executable:" << dir.path() << fileName;
545 return "__executable not found__";
546 }
547
resolveDocUrl(const QString & name)548 QString MenuManager::resolveDocUrl(const QString &name)
549 {
550 QString dirName = this->info[name]["dirname"];
551 QString category = this->info[name]["category"];
552 QString fileName = this->info[name]["filename"];
553
554 if (category == "demos")
555 return this->helpRootUrl + "demos-" + fileName.replace("/", "-") + ".html";
556 else
557 return this->helpRootUrl + dirName.replace("/", "-") + "-" + fileName + ".html";
558 }
559
resolveImageUrl(const QString & name)560 QString MenuManager::resolveImageUrl(const QString &name)
561 {
562 return this->helpRootUrl + "images/" + name;
563 }
564
getHtml(const QString & name)565 QByteArray MenuManager::getHtml(const QString &name)
566 {
567 return getResource(this->resolveDocUrl(name));
568 }
569
getImage(const QString & name)570 QByteArray MenuManager::getImage(const QString &name)
571 {
572 QString imageName = this->info[name]["image"];
573 QString category = this->info[name]["category"];
574 QString fileName = this->info[name]["filename"];
575 bool qml = (this->info[name]["qml"] == QLatin1String("true"));
576 if(qml)
577 fileName = QLatin1String("qml-") + fileName.split('/').last();
578
579 if (imageName.isEmpty()){
580 if (category == "demos")
581 imageName = fileName + "-demo.png";
582 else
583 imageName = fileName + "-example.png";
584 if ((getResource(resolveImageUrl(imageName))).isEmpty())
585 imageName = fileName + ".png";
586 if ((getResource(resolveImageUrl(imageName))).isEmpty())
587 imageName = fileName + "example.png";
588 }
589 return getResource(resolveImageUrl(imageName));
590 }
591
592
createRootMenu(const QDomElement & el)593 void MenuManager::createRootMenu(const QDomElement &el)
594 {
595 QString name = el.attribute("name");
596 createMenu(el, MENU1);
597 createInfo(new MenuContentItem(el, this->window->scene, this->window->mainSceneRoot), name + " -info");
598
599 Movie *menuButtonsIn = this->score->insertMovie(name + " -buttons");
600 Movie *menuButtonsOut = this->score->insertMovie(name + " -buttons -out");
601 createLowLeftButton(QLatin1String("Quit"), QUIT, menuButtonsIn, menuButtonsOut, 0);
602 createLowRightButton("Toggle fullscreen", FULLSCREEN, menuButtonsIn, menuButtonsOut, 0);
603 }
604
createSubMenu(const QDomElement & el)605 void MenuManager::createSubMenu(const QDomElement &el)
606 {
607 QString name = el.attribute("name");
608 createMenu(el, MENU2);
609 createInfo(new MenuContentItem(el, this->window->scene, this->window->mainSceneRoot), name + " -info");
610 }
611
createLeafMenu(const QDomElement & el)612 void MenuManager::createLeafMenu(const QDomElement &el)
613 {
614 QString name = el.attribute("name");
615 createInfo(new ExampleContent(name, this->window->scene, this->window->mainSceneRoot), name);
616
617 Movie *infoButtonsIn = this->score->insertMovie(name + " -buttons");
618 Movie *infoButtonsOut = this->score->insertMovie(name + " -buttons -out");
619 createLowRightLeafButton("Documentation", 600, DOCUMENTATION, infoButtonsIn, infoButtonsOut, 0);
620 if (el.attribute("executable") != "false")
621 createLowRightLeafButton("Launch", 405, LAUNCH, infoButtonsIn, infoButtonsOut, 0);
622 else if(el.attribute("qml") == "true")
623 createLowRightLeafButton("Display", 405, LAUNCH_QML, infoButtonsIn, infoButtonsOut, 0);
624 }
625
createMenu(const QDomElement & category,BUTTON_TYPE type)626 void MenuManager::createMenu(const QDomElement &category, BUTTON_TYPE type)
627 {
628 qreal sw = this->window->scene->sceneRect().width();
629 int xOffset = 15;
630 int yOffset = 10;
631 int maxExamples = Colors::menuCount;
632 int menuIndex = 1;
633 QString name = category.attribute("name");
634 QDomNode currentNode = category.firstChild();
635 QString currentMenu = name + QLatin1String(" -menu") + QString::number(menuIndex);
636
637 while (!currentNode.isNull()){
638 Movie *movieIn = this->score->insertMovie(currentMenu);
639 Movie *movieOut = this->score->insertMovie(currentMenu + " -out");
640 Movie *movieNextTopOut = this->score->insertMovie(currentMenu + " -top_out");
641 Movie *movieNextBottomOut = this->score->insertMovie(currentMenu + " -bottom_out");
642 Movie *movieNextTopIn = this->score->insertMovie(currentMenu + " -top_in");
643 Movie *movieNextBottomIn = this->score->insertMovie(currentMenu + " -bottom_in");
644 Movie *movieShake = this->score->insertMovie(currentMenu + " -shake");
645
646 int i = 0;
647 while (!currentNode.isNull() && i < maxExamples){
648 TextButton *item;
649
650 // create normal menu button
651 QString label = currentNode.toElement().attribute("name");
652 item = new TextButton(label, TextButton::LEFT, type, this->window->scene, this->window->mainSceneRoot);
653 currentNode = currentNode.nextSibling();
654
655 #ifndef QT_OPENGL_SUPPORT
656 if (currentNode.toElement().attribute("dirname") == "opengl")
657 currentNode = currentNode.nextSibling();
658 #endif
659
660 item->setRecursiveVisible(false);
661 item->setZValue(10);
662 qreal ih = item->sceneBoundingRect().height();
663 qreal iw = item->sceneBoundingRect().width();
664 qreal ihp = ih + 3;
665
666 // create in-animation:
667 DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
668 anim->setDuration(float(1000 + (i * 20)) * Colors::animSpeedButtons);
669 anim->setStartPos(QPointF(xOffset, -ih));
670 anim->setPosAt(0.20, QPointF(xOffset, -ih));
671 anim->setPosAt(0.50, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (10 * float(i / 4.0f))));
672 anim->setPosAt(0.60, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
673 anim->setPosAt(0.70, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (5 * float(i / 4.0f))));
674 anim->setPosAt(0.80, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
675 anim->setPosAt(0.90, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (2 * float(i / 4.0f))));
676 anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
677 movieIn->append(anim);
678
679 // create out-animation:
680 anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
681 anim->hideOnFinished = true;
682 anim->setDuration((700 + (30 * i)) * Colors::animSpeedButtons);
683 anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
684 anim->setPosAt(0.60, QPointF(xOffset, 600 - ih - ih));
685 anim->setPosAt(0.65, QPointF(xOffset + 20, 600 - ih));
686 anim->setPosAt(1.00, QPointF(sw + iw, 600 - ih));
687 movieOut->append(anim);
688
689 // create shake-animation:
690 anim = new DemoItemAnimation(item);
691 anim->setDuration(700 * Colors::animSpeedButtons);
692 anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
693 anim->setPosAt(0.55, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY - i*2.0));
694 anim->setPosAt(0.70, QPointF(xOffset - 10, (i * ihp) + yOffset + Colors::contentStartY - i*1.5));
695 anim->setPosAt(0.80, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY - i*1.0));
696 anim->setPosAt(0.90, QPointF(xOffset - 2, (i * ihp) + yOffset + Colors::contentStartY - i*0.5));
697 anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
698 movieShake->append(anim);
699
700 // create next-menu top-out-animation:
701 anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
702 anim->hideOnFinished = true;
703 anim->setDuration((200 + (30 * i)) * Colors::animSpeedButtons);
704 anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
705 anim->setPosAt(0.70, QPointF(xOffset, yOffset + Colors::contentStartY));
706 anim->setPosAt(1.00, QPointF(-iw, yOffset + Colors::contentStartY));
707 movieNextTopOut->append(anim);
708
709 // create next-menu bottom-out-animation:
710 anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
711 anim->hideOnFinished = true;
712 anim->setDuration((200 + (30 * i)) * Colors::animSpeedButtons);
713 anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
714 anim->setPosAt(0.70, QPointF(xOffset, (maxExamples * ihp) + yOffset + Colors::contentStartY));
715 anim->setPosAt(1.00, QPointF(-iw, (maxExamples * ihp) + yOffset + Colors::contentStartY));
716 movieNextBottomOut->append(anim);
717
718 // create next-menu top-in-animation:
719 anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
720 anim->setDuration((700 - (30 * i)) * Colors::animSpeedButtons);
721 anim->setStartPos(QPointF(-iw, yOffset + Colors::contentStartY));
722 anim->setPosAt(0.30, QPointF(xOffset, yOffset + Colors::contentStartY));
723 anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
724 movieNextTopIn->append(anim);
725
726 // create next-menu bottom-in-animation:
727 int reverse = maxExamples - i;
728 anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
729 anim->setDuration((1000 - (30 * reverse)) * Colors::animSpeedButtons);
730 anim->setStartPos(QPointF(-iw, (maxExamples * ihp) + yOffset + Colors::contentStartY));
731 anim->setPosAt(0.30, QPointF(xOffset, (maxExamples * ihp) + yOffset + Colors::contentStartY));
732 anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
733 movieNextBottomIn->append(anim);
734
735 i++;
736 }
737
738 if (!currentNode.isNull() && i == maxExamples){
739 // We need another menu, so register for 'more' and 'back' buttons
740 ++menuIndex;
741 this->info[currentMenu]["more"] = name + QLatin1String(" -menu") + QString::number(menuIndex);
742 currentMenu = name + QLatin1String(" -menu") + QString::number(menuIndex);
743 this->info[currentMenu]["back"] = name + QLatin1String(" -menu") + QString::number(menuIndex - 1);
744 }
745 }
746 }
747
748
createLowLeftButton(const QString & label,BUTTON_TYPE type,Movie * movieIn,Movie * movieOut,Movie * movieShake,const QString & menuString)749 void MenuManager::createLowLeftButton(const QString &label, BUTTON_TYPE type,
750 Movie *movieIn, Movie *movieOut, Movie *movieShake, const QString &menuString)
751 {
752 TextButton *button = new TextButton(label, TextButton::RIGHT, type, this->window->scene, this->window->mainSceneRoot, TextButton::PANEL);
753 if (!menuString.isNull())
754 button->setMenuString(menuString);
755 button->setRecursiveVisible(false);
756 button->setZValue(10);
757
758 qreal iw = button->sceneBoundingRect().width();
759 int xOffset = 15;
760
761 // create in-animation:
762 DemoItemAnimation *buttonIn = new DemoItemAnimation(button, DemoItemAnimation::ANIM_IN);
763 buttonIn->setDuration(1800 * Colors::animSpeedButtons);
764 buttonIn->setStartPos(QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 35));
765 buttonIn->setPosAt(0.5, QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 35));
766 buttonIn->setPosAt(0.7, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
767 buttonIn->setPosAt(1.0, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
768 movieIn->append(buttonIn);
769
770 // create out-animation:
771 DemoItemAnimation *buttonOut = new DemoItemAnimation(button, DemoItemAnimation::ANIM_OUT);
772 buttonOut->hideOnFinished = true;
773 buttonOut->setDuration(400 * Colors::animSpeedButtons);
774 buttonOut->setStartPos(QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
775 buttonOut->setPosAt(1.0, QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 26));
776 movieOut->append(buttonOut);
777
778 if (movieShake){
779 DemoItemAnimation *shakeAnim = new DemoItemAnimation(button, DemoItemAnimation::ANIM_UNSPECIFIED);
780 shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
781 shakeAnim->setDuration(650);
782 shakeAnim->setStartPos(buttonIn->posAt(1.0f));
783 shakeAnim->setPosAt(0.60, buttonIn->posAt(1.0f));
784 shakeAnim->setPosAt(0.70, buttonIn->posAt(1.0f) + QPointF(-3, 0));
785 shakeAnim->setPosAt(0.80, buttonIn->posAt(1.0f) + QPointF(2, 0));
786 shakeAnim->setPosAt(0.90, buttonIn->posAt(1.0f) + QPointF(-1, 0));
787 shakeAnim->setPosAt(1.00, buttonIn->posAt(1.0f));
788 movieShake->append(shakeAnim);
789 }
790 }
791
createLowRightButton(const QString & label,BUTTON_TYPE type,Movie * movieIn,Movie * movieOut,Movie *)792 void MenuManager::createLowRightButton(const QString &label, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie * /*movieShake*/)
793 {
794 TextButton *item = new TextButton(label, TextButton::RIGHT, type, this->window->scene, this->window->mainSceneRoot, TextButton::PANEL);
795 item->setRecursiveVisible(false);
796 item->setZValue(10);
797
798 qreal sw = this->window->scene->sceneRect().width();
799 int xOffset = 70;
800
801 // create in-animation:
802 DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
803 anim->setDuration(1800 * Colors::animSpeedButtons);
804 anim->setStartPos(QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
805 anim->setPosAt(0.5, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
806 anim->setPosAt(0.7, QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 35));
807 anim->setPosAt(1.0, QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 26));
808 movieIn->append(anim);
809
810 // create out-animation:
811 anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
812 anim->hideOnFinished = true;
813 anim->setDuration(400 * Colors::animSpeedButtons);
814 anim->setStartPos(QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 26));
815 anim->setPosAt(1.0, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 26));
816 movieOut->append(anim);
817 }
818
createLowRightLeafButton(const QString & label,int xOffset,BUTTON_TYPE type,Movie * movieIn,Movie * movieOut,Movie *)819 void MenuManager::createLowRightLeafButton(const QString &label, int xOffset, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie * /*movieShake*/)
820 {
821 TextButton *item = new TextButton(label, TextButton::RIGHT, type, this->window->scene, this->window->mainSceneRoot, TextButton::PANEL);
822 item->setRecursiveVisible(false);
823 item->setZValue(10);
824
825 qreal sw = this->window->scene->sceneRect().width();
826 qreal sh = this->window->scene->sceneRect().height();
827
828 // create in-animation:
829 DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
830 anim->setDuration(1050 * Colors::animSpeedButtons);
831 anim->setStartPos(QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
832 anim->setPosAt(0.10, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
833 anim->setPosAt(0.30, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
834 anim->setPosAt(0.35, QPointF(xOffset + 30, Colors::contentStartY + Colors::contentHeight - 35));
835 anim->setPosAt(0.40, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
836 anim->setPosAt(0.45, QPointF(xOffset + 5, Colors::contentStartY + Colors::contentHeight - 35));
837 anim->setPosAt(0.50, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
838 anim->setPosAt(1.00, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
839 movieIn->append(anim);
840
841 // create out-animation:
842 anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
843 anim->hideOnFinished = true;
844 anim->setDuration(300 * Colors::animSpeedButtons);
845 anim->setStartPos(QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
846 anim->setPosAt(1.0, QPointF(xOffset, sh));
847 movieOut->append(anim);
848 }
849
createInfo(DemoItem * item,const QString & name)850 void MenuManager::createInfo(DemoItem *item, const QString &name)
851 {
852 Movie *movie_in = this->score->insertMovie(name);
853 Movie *movie_out = this->score->insertMovie(name + " -out");
854 item->setZValue(8);
855 item->setRecursiveVisible(false);
856
857 float xOffset = 230.0f;
858 DemoItemAnimation *infoIn = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
859 infoIn->timeline->setCurveShape(QTimeLine::LinearCurve);
860 infoIn->setDuration(650);
861 infoIn->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY));
862 infoIn->setPosAt(0.60, QPointF(xOffset, Colors::contentStartY));
863 infoIn->setPosAt(0.70, QPointF(xOffset + 20, Colors::contentStartY));
864 infoIn->setPosAt(0.80, QPointF(xOffset, Colors::contentStartY));
865 infoIn->setPosAt(0.90, QPointF(xOffset + 7, Colors::contentStartY));
866 infoIn->setPosAt(1.00, QPointF(xOffset, Colors::contentStartY));
867 movie_in->append(infoIn);
868
869 DemoItemAnimation *infoOut = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
870 infoOut->timeline->setCurveShape(QTimeLine::EaseInCurve);
871 infoOut->setDuration(300);
872 infoOut->hideOnFinished = true;
873 infoOut->setStartPos(QPointF(xOffset, Colors::contentStartY));
874 infoOut->setPosAt(1.0, QPointF(-600, Colors::contentStartY));
875 movie_out->append(infoOut);
876 }
877
createTicker()878 void MenuManager::createTicker()
879 {
880 if (!Colors::noTicker){
881 Movie *movie_in = this->score->insertMovie("ticker");
882 Movie *movie_out = this->score->insertMovie("ticker -out");
883 Movie *movie_activate = this->score->insertMovie("ticker -activate");
884 Movie *movie_deactivate = this->score->insertMovie("ticker -deactivate");
885
886 this->ticker = new ItemCircleAnimation(this->window->scene, 0);
887 this->ticker->setZValue(50);
888 this->ticker->hide();
889
890 // Move ticker in:
891 int qtendpos = 485;
892 int qtPosY = 120;
893 this->tickerInAnim = new DemoItemAnimation(this->ticker, DemoItemAnimation::ANIM_IN);
894 this->tickerInAnim->setDuration(500);
895 this->tickerInAnim->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY + qtPosY));
896 this->tickerInAnim->setPosAt(0.60, QPointF(qtendpos, Colors::contentStartY + qtPosY));
897 this->tickerInAnim->setPosAt(0.70, QPointF(qtendpos + 30, Colors::contentStartY + qtPosY));
898 this->tickerInAnim->setPosAt(0.80, QPointF(qtendpos, Colors::contentStartY + qtPosY));
899 this->tickerInAnim->setPosAt(0.90, QPointF(qtendpos + 5, Colors::contentStartY + qtPosY));
900 this->tickerInAnim->setPosAt(1.00, QPointF(qtendpos, Colors::contentStartY + qtPosY));
901 movie_in->append(this->tickerInAnim);
902
903 // Move ticker out:
904 DemoItemAnimation *qtOut = new DemoItemAnimation(this->ticker, DemoItemAnimation::ANIM_OUT);
905 qtOut->hideOnFinished = true;
906 qtOut->setDuration(500);
907 qtOut->setStartPos(QPointF(qtendpos, Colors::contentStartY + qtPosY));
908 qtOut->setPosAt(1.00, QPointF(this->window->scene->sceneRect().width() + 700, Colors::contentStartY + qtPosY));
909 movie_out->append(qtOut);
910
911 // Move ticker in on activate:
912 DemoItemAnimation *qtActivate = new DemoItemAnimation(this->ticker);
913 qtActivate->setDuration(400);
914 qtActivate->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY + qtPosY));
915 qtActivate->setPosAt(0.60, QPointF(qtendpos, Colors::contentStartY + qtPosY));
916 qtActivate->setPosAt(0.70, QPointF(qtendpos + 30, Colors::contentStartY + qtPosY));
917 qtActivate->setPosAt(0.80, QPointF(qtendpos, Colors::contentStartY + qtPosY));
918 qtActivate->setPosAt(0.90, QPointF(qtendpos + 5, Colors::contentStartY + qtPosY));
919 qtActivate->setPosAt(1.00, QPointF(qtendpos, Colors::contentStartY + qtPosY));
920 movie_activate->append(qtActivate);
921
922 // Move ticker out on deactivate:
923 DemoItemAnimation *qtDeactivate = new DemoItemAnimation(this->ticker);
924 qtDeactivate->hideOnFinished = true;
925 qtDeactivate->setDuration(400);
926 qtDeactivate->setStartPos(QPointF(qtendpos, Colors::contentStartY + qtPosY));
927 qtDeactivate->setPosAt(1.00, QPointF(qtendpos, 800));
928 movie_deactivate->append(qtDeactivate);
929 }
930 }
931
createUpnDownButtons()932 void MenuManager::createUpnDownButtons()
933 {
934 float xOffset = 15.0f;
935 float yOffset = 450.0f;
936
937 this->upButton = new TextButton("", TextButton::LEFT, MenuManager::UP, this->window->scene, this->window->mainSceneRoot, TextButton::UP);
938 this->upButton->prepare();
939 this->upButton->setPos(xOffset, yOffset);
940 this->upButton->setState(TextButton::DISABLED);
941
942 this->downButton = new TextButton("", TextButton::LEFT, MenuManager::DOWN, this->window->scene, this->window->mainSceneRoot, TextButton::DOWN);
943 this->downButton->prepare();
944 this->downButton->setPos(xOffset + 10 + this->downButton->sceneBoundingRect().width(), yOffset);
945
946 Movie *movieShake = this->score->insertMovie("upndown -shake");
947
948 DemoItemAnimation *shakeAnim = new DemoItemAnimation(this->upButton, DemoItemAnimation::ANIM_UNSPECIFIED);
949 shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
950 shakeAnim->setDuration(650);
951 shakeAnim->setStartPos(this->upButton->pos());
952 shakeAnim->setPosAt(0.60, this->upButton->pos());
953 shakeAnim->setPosAt(0.70, this->upButton->pos() + QPointF(-2, 0));
954 shakeAnim->setPosAt(0.80, this->upButton->pos() + QPointF(1, 0));
955 shakeAnim->setPosAt(0.90, this->upButton->pos() + QPointF(-1, 0));
956 shakeAnim->setPosAt(1.00, this->upButton->pos());
957 movieShake->append(shakeAnim);
958
959 shakeAnim = new DemoItemAnimation(this->downButton, DemoItemAnimation::ANIM_UNSPECIFIED);
960 shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
961 shakeAnim->setDuration(650);
962 shakeAnim->setStartPos(this->downButton->pos());
963 shakeAnim->setPosAt(0.60, this->downButton->pos());
964 shakeAnim->setPosAt(0.70, this->downButton->pos() + QPointF(-5, 0));
965 shakeAnim->setPosAt(0.80, this->downButton->pos() + QPointF(-3, 0));
966 shakeAnim->setPosAt(0.90, this->downButton->pos() + QPointF(-1, 0));
967 shakeAnim->setPosAt(1.00, this->downButton->pos());
968 movieShake->append(shakeAnim);
969 }
970
createBackButton()971 void MenuManager::createBackButton()
972 {
973 Movie *backIn = this->score->insertMovie("back -in");
974 Movie *backOut = this->score->insertMovie("back -out");
975 Movie *backShake = this->score->insertMovie("back -shake");
976 createLowLeftButton(QLatin1String("Back"), ROOT, backIn, backOut, backShake, Colors::rootMenuName);
977 }
978