demos/qtdemo/menumanager.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demos/qtdemo/menumanager.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,874 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "menumanager.h"
+#include "colors.h"
+#include "menucontent.h"
+#include "examplecontent.h"
+
+MenuManager *MenuManager::pInstance = 0;
+
+MenuManager * MenuManager::instance()
+{
+    if (!MenuManager::pInstance)
+        MenuManager::pInstance = new MenuManager();
+    return MenuManager::pInstance;
+}
+
+MenuManager::MenuManager()
+{
+    this->ticker = 0;
+    this->tickerInAnim = 0;
+    this->upButton = 0;
+    this->downButton = 0;
+    this->helpEngine = 0;
+    this->score = new Score();
+    this->currentMenu = QLatin1String("[no menu visible]");
+    this->currentCategory = QLatin1String("[no category visible]");
+    this->currentMenuButtons = QLatin1String("[no menu buttons visible]");
+    this->currentInfo = QLatin1String("[no info visible]");
+    this->currentMenuCode = -1;
+    this->readXmlDocument();
+    this->initHelpEngine();
+}
+
+MenuManager::~MenuManager()
+{
+    delete this->score;
+    delete this->contentsDoc;
+    delete this->helpEngine;
+}
+
+QByteArray MenuManager::getResource(const QString &name)
+{
+    QByteArray ba = this->helpEngine->fileData(name);
+    if (Colors::verbose && ba.isEmpty())
+        qDebug() << " - WARNING: Could not get " << name;
+    return ba;
+}
+
+void MenuManager::readXmlDocument()
+{
+    this->contentsDoc = new QDomDocument();
+    QString errorStr;
+    int errorLine;
+    int errorColumn;
+
+    QFile file(":/xml/examples.xml");
+    bool statusOK = this->contentsDoc->setContent(&file, true, &errorStr, &errorLine, &errorColumn);
+    if (!statusOK){
+        QMessageBox::critical(0,
+                              QObject::tr("DOM Parser"),
+                              QObject::tr("Could not read or find the contents document. Error at line %1, column %2:\n%3")
+                              .arg(errorLine).arg(errorColumn).arg(errorStr)
+                              );
+        exit(-1);
+    }
+}
+
+void MenuManager::initHelpEngine()
+{
+    this->helpRootUrl = QString("qthelp://com.trolltech.qt.%1%2%3/qdoc/")
+        .arg(QT_VERSION >> 16).arg((QT_VERSION >> 8) & 0xFF)
+        .arg(QT_VERSION & 0xFF);
+
+    // Store help collection file in cache dir of assistant
+    QString cacheDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation)
+                     + QLatin1String("/Trolltech/Assistant/");
+    QString helpDataFile = QString(QLatin1String("qtdemo_%1.qhc")).arg(QLatin1String(QT_VERSION_STR));
+
+    QDir dir;
+    if (!dir.exists(cacheDir))
+        dir.mkpath(cacheDir);
+
+    // Create help engine (and new
+    // helpDataFile if it does not exist):
+    this->helpEngine = new QHelpEngineCore(cacheDir + helpDataFile);
+    this->helpEngine->setupData();
+
+    QString qtDocRoot = QLibraryInfo::location(QLibraryInfo::DocumentationPath) + QLatin1String("/qch");
+    qtDocRoot = QDir(qtDocRoot).absolutePath();
+
+    QStringList qchFiles;
+    qchFiles << QLatin1String("/qt.qch")
+             << QLatin1String("/designer.qch")
+             << QLatin1String("/linguist.qch");
+
+    QString oldDir = helpEngine->customValue(QLatin1String("docDir"), QString()).toString();
+    if (oldDir != qtDocRoot) {
+        foreach (const QString &qchFile, qchFiles)
+            helpEngine->unregisterDocumentation(QHelpEngineCore::namespaceName(qtDocRoot + qchFile));
+    }
+
+    // If the data that the engine will work
+    // on is not yet registered, do it now:
+    foreach (const QString &qchFile, qchFiles)
+        helpEngine->registerDocumentation(qtDocRoot + qchFile);
+
+    helpEngine->setCustomValue(QLatin1String("docDir"), qtDocRoot);
+}
+
+void MenuManager::itemSelected(int userCode, const QString &menuName)
+{
+    switch (userCode){
+    case LAUNCH:
+        this->launchExample(this->currentInfo);
+        break;
+    case DOCUMENTATION:
+        this->showDocInAssistant(this->currentInfo);
+        break;
+    case QUIT:
+        this->window->loop = false;
+        QCoreApplication::quit();
+        break;
+    case FULLSCREEN:
+        this->window->toggleFullscreen();
+        break;
+    case ROOT:
+        // out:
+        this->score->queueMovie(this->currentMenu + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+        this->score->queueMovie(this->currentMenuButtons + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+        this->score->queueMovie(this->currentInfo + " -out");
+        this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
+        this->score->queueMovie("back -out", Score::ONLY_IF_VISIBLE);
+        // book-keeping:
+        this->currentMenuCode = ROOT;
+        this->currentMenu = menuName + " -menu1";
+        this->currentMenuButtons = menuName + " -buttons";
+        this->currentInfo = menuName + " -info";
+        // in:
+        this->score->queueMovie("upndown -shake");
+        this->score->queueMovie(this->currentMenu, Score::FROM_START, Score::UNLOCK_ITEMS);
+        this->score->queueMovie(this->currentMenuButtons, Score::FROM_START, Score::UNLOCK_ITEMS);
+        this->score->queueMovie(this->currentInfo);
+        if (!Colors::noTicker){
+            this->ticker->doIntroTransitions = true;
+            this->tickerInAnim->startDelay = 2000;
+            this->ticker->useGuideQt();
+            this->score->queueMovie("ticker", Score::NEW_ANIMATION_ONLY);
+        }
+        break;
+    case MENU1:
+        // out:
+        this->score->queueMovie(this->currentMenu + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+        this->score->queueMovie(this->currentMenuButtons + " -out", Score::FROM_START, Score::LOCK_ITEMS);
+        this->score->queueMovie(this->currentInfo + " -out");
+        // book-keeping:
+        this->currentMenuCode = MENU1;
+        this->currentCategory = menuName;
+        this->currentMenu = menuName + " -menu1";
+        this->currentInfo = menuName + " -info";
+        // in:
+        this->score->queueMovie("upndown -shake");
+        this->score->queueMovie("back -in");
+        this->score->queueMovie(this->currentMenu, Score::FROM_START, Score::UNLOCK_ITEMS);
+        this->score->queueMovie(this->currentInfo);
+        if (!Colors::noTicker)
+            this->ticker->useGuideTt();
+        break;
+    case MENU2:
+        // out:
+        this->score->queueMovie(this->currentInfo + " -out", Score::NEW_ANIMATION_ONLY);
+        this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
+        // book-keeping:
+        this->currentMenuCode = MENU2;
+        this->currentInfo = menuName;
+        // in / shake:
+        this->score->queueMovie("upndown -shake");
+        this->score->queueMovie("back -shake");
+        this->score->queueMovie(this->currentMenu + " -shake");
+        this->score->queueMovie(this->currentInfo, Score::NEW_ANIMATION_ONLY);
+        this->score->queueMovie(this->currentInfo + " -buttons", Score::NEW_ANIMATION_ONLY);
+        if (!Colors::noTicker){
+            this->score->queueMovie("ticker -out", Score::NEW_ANIMATION_ONLY);
+        }
+        break;
+    case UP:{
+        QString backMenu = this->info[this->currentMenu]["back"];
+        if (!backMenu.isNull()){
+            this->score->queueMovie(this->currentMenu + " -top_out", Score::FROM_START, Score::LOCK_ITEMS);
+            this->score->queueMovie(backMenu + " -bottom_in", Score::FROM_START, Score::UNLOCK_ITEMS);
+            this->currentMenu = backMenu;
+        }
+        break; }
+    case DOWN:{
+        QString moreMenu = this->info[this->currentMenu]["more"];
+        if (!moreMenu.isNull()){
+            this->score->queueMovie(this->currentMenu + " -bottom_out", Score::FROM_START, Score::LOCK_ITEMS);
+            this->score->queueMovie(moreMenu + " -top_in", Score::FROM_START, Score::UNLOCK_ITEMS);
+            this->currentMenu = moreMenu;
+        }
+        break; }
+    case BACK:{
+        if (this->currentMenuCode == MENU2){
+            // out:
+            this->score->queueMovie(this->currentInfo + " -out", Score::NEW_ANIMATION_ONLY);
+            this->score->queueMovie(this->currentInfo + " -buttons -out", Score::NEW_ANIMATION_ONLY);
+            // book-keeping:
+            this->currentMenuCode = MENU1;
+            this->currentMenuButtons = this->currentCategory + " -buttons";
+            this->currentInfo = this->currentCategory + " -info";
+            // in / shake:
+            this->score->queueMovie("upndown -shake");
+            this->score->queueMovie(this->currentMenu + " -shake");
+            this->score->queueMovie(this->currentInfo, Score::NEW_ANIMATION_ONLY);
+            this->score->queueMovie(this->currentInfo + " -buttons", Score::NEW_ANIMATION_ONLY);
+            if (!Colors::noTicker){
+                this->ticker->doIntroTransitions = false;
+                this->tickerInAnim->startDelay = 500;
+                this->score->queueMovie("ticker", Score::NEW_ANIMATION_ONLY);
+            }
+        } else if (this->currentMenuCode != ROOT)
+            itemSelected(ROOT, Colors::rootMenuName);
+        break; }
+    }
+
+    // update back- and more buttons
+    bool noBackMenu = this->info[this->currentMenu]["back"].isNull();
+    bool noMoreMenu = this->info[this->currentMenu]["more"].isNull();
+    this->upButton->setState(noBackMenu ? TextButton::DISABLED : TextButton::OFF);
+    this->downButton->setState(noMoreMenu ? TextButton::DISABLED : TextButton::OFF);
+
+    if (this->score->hasQueuedMovies()){
+        this->score->playQue();
+        // Playing new movies might include
+        // loading etc. So ignore the FPS
+        // at this point
+        this->window->fpsHistory.clear();
+    }
+}
+
+void MenuManager::showDocInAssistant(const QString &name)
+{
+    QString url = this->resolveDocUrl(name);
+    if (Colors::verbose)
+        qDebug() << "Sending URL to Assistant:" << url;
+
+    // Start assistant if it's not already running:
+    if (this->assistantProcess.state() != QProcess::Running){
+        QString app = QLibraryInfo::location(QLibraryInfo::BinariesPath) + QDir::separator();
+#if !defined(Q_OS_MAC)
+        app += QLatin1String("assistant");
+#else
+        app += QLatin1String("Assistant.app/Contents/MacOS/Assistant");
+#endif
+        QStringList args;
+        args << QLatin1String("-enableRemoteControl");
+        this->assistantProcess.start(app, args);
+        if (!this->assistantProcess.waitForStarted()) {
+            QMessageBox::critical(0, tr("Qt Demo"), tr("Could not start Qt Assistant.").arg(app));
+            return;
+        }
+    }
+
+    // Send command through remote control even if the process
+    // was started to activate assistant and bring it to front:
+    QTextStream str(&this->assistantProcess);
+    str << "SetSource " << url << QLatin1Char('\0') << endl;
+}
+
+void MenuManager::launchExample(const QString &name)
+{
+    QString executable = this->resolveExeFile(name);
+#ifdef Q_OS_MAC
+    if (Colors::verbose)
+        qDebug() << "Launching:" << executable;
+    bool success = QDesktopServices::openUrl(QUrl::fromLocalFile(executable));
+    if (!success){
+        QMessageBox::critical(0, tr("Failed to launch the example"),
+                          tr("Could not launch the example. Ensure that it has been built."),
+                          QMessageBox::Cancel);
+    }
+#else // Not mac. To not break anything regarding dll's etc, keep it the way it was before:
+    QProcess *process = new QProcess(this);
+    connect(process, SIGNAL(finished(int)), this, SLOT(exampleFinished()));
+    connect(process, SIGNAL(error(QProcess::ProcessError)), this, SLOT(exampleError(QProcess::ProcessError)));
+
+#ifdef Q_OS_WIN
+    //make sure it finds the dlls on windows
+    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+    env.insert(QLatin1String("PATH"), QLibraryInfo::location(QLibraryInfo::BinariesPath) 
+               + QLatin1Char(';') + env.value(QLatin1String("Path")));
+    process->setProcessEnvironment(env);
+#endif
+
+    if (info[name]["changedirectory"] != "false"){
+        QString workingDirectory = resolveDataDir(name);
+        process->setWorkingDirectory(workingDirectory);
+        if (Colors::verbose)
+            qDebug() << "Setting working directory:" << workingDirectory;
+    }
+
+    if (Colors::verbose)
+        qDebug() << "Launching:" << executable;
+    process->start(executable);
+#endif
+}
+
+void MenuManager::exampleFinished()
+{
+}
+
+void MenuManager::exampleError(QProcess::ProcessError error)
+{
+    if (error != QProcess::Crashed)
+        QMessageBox::critical(0, tr("Failed to launch the example"),
+                          tr("Could not launch the example. Ensure that it has been built."),
+                          QMessageBox::Cancel);
+}
+
+void MenuManager::init(MainWindow *window)
+{
+    this->window = window;
+
+    // Create div:
+    this->createTicker();
+    this->createUpnDownButtons();
+    this->createBackButton();
+
+    // Create first level menu:
+    QDomElement rootElement = this->contentsDoc->documentElement();
+    this->createRootMenu(rootElement);
+
+    // Create second level menus:
+    QDomNode level2MenuNode = rootElement.firstChild();
+    while (!level2MenuNode.isNull()){
+        QDomElement level2MenuElement = level2MenuNode.toElement();
+        this->createSubMenu(level2MenuElement);
+
+        // create leaf menu and example info:
+        QDomNode exampleNode = level2MenuElement.firstChild();
+        while (!exampleNode.isNull()){
+            QDomElement exampleElement = exampleNode.toElement();
+            this->readInfoAboutExample(exampleElement);
+            this->createLeafMenu(exampleElement);
+            exampleNode = exampleNode.nextSibling();
+        }
+
+        level2MenuNode = level2MenuNode.nextSibling();
+    }
+}
+
+void MenuManager::readInfoAboutExample(const QDomElement &example)
+{
+    QString name = example.attribute("name");
+    if (this->info.contains(name))
+        qWarning() << "__WARNING: MenuManager::readInfoAboutExample: Demo/example with name"
+                    << name << "appears twize in the xml-file!__";
+
+    this->info[name]["filename"] = example.attribute("filename");
+    this->info[name]["category"] = example.parentNode().toElement().tagName();
+    this->info[name]["dirname"] = example.parentNode().toElement().attribute("dirname");
+    this->info[name]["changedirectory"] = example.attribute("changedirectory");
+    this->info[name]["image"] = example.attribute("image");
+}
+
+QString MenuManager::resolveDataDir(const QString &name)
+{
+    QString dirName = this->info[name]["dirname"];
+    QString category = this->info[name]["category"];
+    QString fileName = this->info[name]["filename"];
+
+    QDir dir;
+    if (category == "demos")
+        dir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
+    else
+        dir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
+
+    dir.cd(dirName);
+    dir.cd(fileName);
+    return dir.absolutePath();
+}
+
+QString MenuManager::resolveExeFile(const QString &name)
+{
+    QString dirName = this->info[name]["dirname"];
+    QString category = this->info[name]["category"];
+    QString fileName = this->info[name]["filename"];
+
+    QDir dir;
+    if (category == "demos")
+        dir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
+    else
+        dir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
+
+    dir.cd(dirName);
+    dir.cd(fileName);
+
+    QFile unixFile(dir.path() + "/" + fileName);
+    if (unixFile.exists()) return unixFile.fileName();
+    QFile winR(dir.path() + "\\release\\" + fileName + ".exe");
+    if (winR.exists()) return winR.fileName();
+    QFile winD(dir.path() + "\\debug\\" + fileName + ".exe");
+    if (winD.exists()) return winD.fileName();
+    QFile mac(dir.path() + "/" + fileName + ".app");
+    if (mac.exists()) return mac.fileName();
+
+    if (Colors::verbose)
+        qDebug() << "- WARNING: Could not resolve executable:" << dir.path() << fileName;
+    return "__executable not found__";
+}
+
+QString MenuManager::resolveDocUrl(const QString &name)
+{
+    QString dirName = this->info[name]["dirname"];
+    QString category = this->info[name]["category"];
+    QString fileName = this->info[name]["filename"];
+
+    if (category == "demos")
+        return this->helpRootUrl + "demos-" + fileName + ".html";
+    else
+        return this->helpRootUrl + dirName.replace("/", "-") + "-" + fileName + ".html";
+}
+
+QString MenuManager::resolveImageUrl(const QString &name)
+{
+    return this->helpRootUrl + "images/" + name;
+}
+
+QByteArray MenuManager::getHtml(const QString &name)
+{
+    return getResource(this->resolveDocUrl(name));
+}
+
+QByteArray MenuManager::getImage(const QString &name)
+{
+    QString imageName = this->info[name]["image"];
+    QString category = this->info[name]["category"];
+    QString fileName = this->info[name]["filename"];
+
+    if (imageName.isEmpty()){
+        if (category == "demos")
+            imageName = fileName + "-demo.png";
+        else
+            imageName = fileName + "-example.png";
+        if ((getResource(resolveImageUrl(imageName))).isEmpty())
+            imageName = fileName + ".png";
+        if ((getResource(resolveImageUrl(imageName))).isEmpty())
+            imageName = fileName + "example.png";
+    }
+    return getResource(resolveImageUrl(imageName));
+}
+
+
+void MenuManager::createRootMenu(const QDomElement &el)
+{
+    QString name = el.attribute("name");
+    createMenu(el, MENU1);
+    createInfo(new MenuContentItem(el, this->window->scene, 0), name + " -info");
+
+    Movie *menuButtonsIn = this->score->insertMovie(name + " -buttons");
+    Movie *menuButtonsOut = this->score->insertMovie(name + " -buttons -out");
+    createLowLeftButton(QLatin1String("Quit"), QUIT, menuButtonsIn, menuButtonsOut, 0);
+    createLowRightButton("Toggle fullscreen", FULLSCREEN, menuButtonsIn, menuButtonsOut, 0);
+}
+
+void MenuManager::createSubMenu(const QDomElement &el)
+{
+    QString name = el.attribute("name");
+    createMenu(el, MENU2);
+    createInfo(new MenuContentItem(el, this->window->scene, 0), name + " -info");
+}
+
+void MenuManager::createLeafMenu(const QDomElement &el)
+{
+    QString name = el.attribute("name");
+    createInfo(new ExampleContent(name, this->window->scene, 0), name);
+
+    Movie *infoButtonsIn = this->score->insertMovie(name + " -buttons");
+    Movie *infoButtonsOut = this->score->insertMovie(name + " -buttons -out");
+    createLowRightLeafButton("Documentation", 600, DOCUMENTATION, infoButtonsIn, infoButtonsOut, 0);
+    if (el.attribute("executable") != "false")
+        createLowRightLeafButton("Launch", 405, LAUNCH, infoButtonsIn, infoButtonsOut, 0);
+}
+
+void MenuManager::createMenu(const QDomElement &category, BUTTON_TYPE type)
+{
+    qreal sw = this->window->scene->sceneRect().width();
+    int xOffset = 15;
+    int yOffset = 10;
+    int maxExamples = Colors::menuCount;
+    int menuIndex = 1;
+    QString name = category.attribute("name");
+    QDomNode currentNode = category.firstChild();
+    QString currentMenu = name + QLatin1String(" -menu") + QString::number(menuIndex);
+
+    while (!currentNode.isNull()){
+        Movie *movieIn = this->score->insertMovie(currentMenu);
+        Movie *movieOut = this->score->insertMovie(currentMenu + " -out");
+        Movie *movieNextTopOut = this->score->insertMovie(currentMenu + " -top_out");
+        Movie *movieNextBottomOut = this->score->insertMovie(currentMenu + " -bottom_out");
+        Movie *movieNextTopIn = this->score->insertMovie(currentMenu + " -top_in");
+        Movie *movieNextBottomIn = this->score->insertMovie(currentMenu + " -bottom_in");
+        Movie *movieShake = this->score->insertMovie(currentMenu + " -shake");
+
+        int i = 0;
+        while (!currentNode.isNull() && i < maxExamples){
+            TextButton *item;
+
+            // create normal menu button
+            QString label = currentNode.toElement().attribute("name");
+            item = new TextButton(label, TextButton::LEFT, type, this->window->scene, 0);
+            currentNode = currentNode.nextSibling();
+
+#ifndef QT_OPENGL_SUPPORT
+            if (currentNode.toElement().attribute("dirname") == "opengl")
+                currentNode = currentNode.nextSibling();
+#endif
+
+            item->setRecursiveVisible(false);
+            item->setZValue(10);
+            qreal ih = item->sceneBoundingRect().height();
+            qreal iw = item->sceneBoundingRect().width();
+            qreal ihp = ih + 3;
+
+            // create in-animation:
+            DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+            anim->setDuration(float(1000 + (i * 20)) * Colors::animSpeedButtons);
+            anim->setStartPos(QPointF(xOffset, -ih));
+            anim->setPosAt(0.20, QPointF(xOffset, -ih));
+            anim->setPosAt(0.50, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (10 * float(i / 4.0f))));
+            anim->setPosAt(0.60, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(0.70, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (5 * float(i / 4.0f))));
+            anim->setPosAt(0.80, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(0.90, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY + (2 * float(i / 4.0f))));
+            anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            movieIn->append(anim);
+
+            // create out-animation:
+            anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+            anim->hideOnFinished = true;
+            anim->setDuration((700 + (30 * i)) * Colors::animSpeedButtons);
+            anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(0.60, QPointF(xOffset, 600 - ih - ih));
+            anim->setPosAt(0.65, QPointF(xOffset + 20, 600 - ih));
+            anim->setPosAt(1.00, QPointF(sw + iw, 600 - ih));
+            movieOut->append(anim);
+
+            // create shake-animation:
+            anim = new DemoItemAnimation(item);
+            anim->setDuration(700 * Colors::animSpeedButtons);
+            anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(0.55, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY - i*2.0));
+            anim->setPosAt(0.70, QPointF(xOffset - 10, (i * ihp) + yOffset + Colors::contentStartY - i*1.5));
+            anim->setPosAt(0.80, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY - i*1.0));
+            anim->setPosAt(0.90, QPointF(xOffset - 2, (i * ihp) + yOffset + Colors::contentStartY - i*0.5));
+            anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            movieShake->append(anim);
+
+            // create next-menu top-out-animation:
+            anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+            anim->hideOnFinished = true;
+            anim->setDuration((200 + (30 * i)) * Colors::animSpeedButtons);
+            anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(0.70, QPointF(xOffset, yOffset + Colors::contentStartY));
+            anim->setPosAt(1.00, QPointF(-iw, yOffset + Colors::contentStartY));
+            movieNextTopOut->append(anim);
+
+            // create next-menu bottom-out-animation:
+            anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+            anim->hideOnFinished = true;
+            anim->setDuration((200 + (30 * i)) * Colors::animSpeedButtons);
+            anim->setStartPos(QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(0.70, QPointF(xOffset, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(1.00, QPointF(-iw, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+            movieNextBottomOut->append(anim);
+
+            // create next-menu top-in-animation:
+            anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+            anim->setDuration((700 - (30 * i)) * Colors::animSpeedButtons);
+            anim->setStartPos(QPointF(-iw, yOffset + Colors::contentStartY));
+            anim->setPosAt(0.30, QPointF(xOffset, yOffset + Colors::contentStartY));
+            anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            movieNextTopIn->append(anim);
+
+            // create next-menu bottom-in-animation:
+            int reverse = maxExamples - i;
+            anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+            anim->setDuration((1000 - (30 * reverse)) * Colors::animSpeedButtons);
+            anim->setStartPos(QPointF(-iw, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(0.30, QPointF(xOffset, (maxExamples * ihp) + yOffset + Colors::contentStartY));
+            anim->setPosAt(1.00, QPointF(xOffset, (i * ihp) + yOffset + Colors::contentStartY));
+            movieNextBottomIn->append(anim);
+
+            i++;
+        }
+
+        if (!currentNode.isNull() && i == maxExamples){
+            // We need another menu, so register for 'more' and 'back' buttons
+            ++menuIndex;
+            this->info[currentMenu]["more"] = name + QLatin1String(" -menu") + QString::number(menuIndex);
+            currentMenu = name + QLatin1String(" -menu") + QString::number(menuIndex);
+            this->info[currentMenu]["back"] = name + QLatin1String(" -menu") + QString::number(menuIndex - 1);
+        }
+    }
+}
+
+
+void MenuManager::createLowLeftButton(const QString &label, BUTTON_TYPE type,
+    Movie *movieIn, Movie *movieOut, Movie *movieShake, const QString &menuString)
+{
+    TextButton *button = new TextButton(label, TextButton::RIGHT, type, this->window->scene, 0, TextButton::PANEL);
+    if (!menuString.isNull())
+        button->setMenuString(menuString);
+    button->setRecursiveVisible(false);
+    button->setZValue(10);
+
+    qreal iw = button->sceneBoundingRect().width();
+    int xOffset = 15;
+
+    // create in-animation:
+    DemoItemAnimation *buttonIn = new DemoItemAnimation(button, DemoItemAnimation::ANIM_IN);
+    buttonIn->setDuration(1800 * Colors::animSpeedButtons);
+    buttonIn->setStartPos(QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 35));
+    buttonIn->setPosAt(0.5, QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 35));
+    buttonIn->setPosAt(0.7, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+    buttonIn->setPosAt(1.0, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+    movieIn->append(buttonIn);
+
+    // create out-animation:
+    DemoItemAnimation *buttonOut = new DemoItemAnimation(button, DemoItemAnimation::ANIM_OUT);
+    buttonOut->hideOnFinished = true;
+    buttonOut->setDuration(400 * Colors::animSpeedButtons);
+    buttonOut->setStartPos(QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+    buttonOut->setPosAt(1.0, QPointF(-iw, Colors::contentStartY + Colors::contentHeight - 26));
+    movieOut->append(buttonOut);
+
+    if (movieShake){
+        DemoItemAnimation *shakeAnim = new DemoItemAnimation(button, DemoItemAnimation::ANIM_UNSPECIFIED);
+        shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
+        shakeAnim->setDuration(650);
+        shakeAnim->setStartPos(buttonIn->posAt(1.0f));
+        shakeAnim->setPosAt(0.60, buttonIn->posAt(1.0f));
+        shakeAnim->setPosAt(0.70, buttonIn->posAt(1.0f) + QPointF(-3, 0));
+        shakeAnim->setPosAt(0.80, buttonIn->posAt(1.0f) + QPointF(2, 0));
+        shakeAnim->setPosAt(0.90, buttonIn->posAt(1.0f) + QPointF(-1, 0));
+        shakeAnim->setPosAt(1.00, buttonIn->posAt(1.0f));
+        movieShake->append(shakeAnim);
+    }
+}
+
+void MenuManager::createLowRightButton(const QString &label, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie * /*movieShake*/)
+{
+    TextButton *item = new TextButton(label, TextButton::RIGHT, type, this->window->scene, 0, TextButton::PANEL);
+    item->setRecursiveVisible(false);
+    item->setZValue(10);
+
+    qreal sw = this->window->scene->sceneRect().width();
+    int xOffset = 70;
+
+    // create in-animation:
+    DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+    anim->setDuration(1800 * Colors::animSpeedButtons);
+    anim->setStartPos(QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.5, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.7, QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(1.0, QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 26));
+    movieIn->append(anim);
+
+    // create out-animation:
+    anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+    anim->hideOnFinished = true;
+    anim->setDuration(400 * Colors::animSpeedButtons);
+    anim->setStartPos(QPointF(xOffset + 535, Colors::contentStartY + Colors::contentHeight - 26));
+    anim->setPosAt(1.0, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 26));
+    movieOut->append(anim);
+}
+
+void MenuManager::createLowRightLeafButton(const QString &label, int xOffset, BUTTON_TYPE type, Movie *movieIn, Movie *movieOut, Movie * /*movieShake*/)
+{
+    TextButton *item = new TextButton(label, TextButton::RIGHT, type, this->window->scene, 0, TextButton::PANEL);
+    item->setRecursiveVisible(false);
+    item->setZValue(10);
+
+    qreal sw = this->window->scene->sceneRect().width();
+    qreal sh = this->window->scene->sceneRect().height();
+
+    // create in-animation:
+    DemoItemAnimation *anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+    anim->setDuration(1050 * Colors::animSpeedButtons);
+    anim->setStartPos(QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.10, QPointF(sw, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.30, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.35, QPointF(xOffset + 30, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.40, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.45, QPointF(xOffset + 5, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(0.50, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 35));
+    anim->setPosAt(1.00, QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+    movieIn->append(anim);
+
+    // create out-animation:
+    anim = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+    anim->hideOnFinished = true;
+    anim->setDuration(300 * Colors::animSpeedButtons);
+    anim->setStartPos(QPointF(xOffset, Colors::contentStartY + Colors::contentHeight - 26));
+    anim->setPosAt(1.0, QPointF(xOffset, sh));
+    movieOut->append(anim);
+}
+
+void MenuManager::createInfo(DemoItem *item, const QString &name)
+{
+    Movie *movie_in = this->score->insertMovie(name);
+    Movie *movie_out = this->score->insertMovie(name + " -out");
+    item->setZValue(8);
+    item->setRecursiveVisible(false);
+
+    float xOffset = 230.0f;
+    DemoItemAnimation *infoIn = new DemoItemAnimation(item, DemoItemAnimation::ANIM_IN);
+    infoIn->timeline->setCurveShape(QTimeLine::LinearCurve);
+    infoIn->setDuration(650);
+    infoIn->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY));
+    infoIn->setPosAt(0.60, QPointF(xOffset, Colors::contentStartY));
+    infoIn->setPosAt(0.70, QPointF(xOffset + 20, Colors::contentStartY));
+    infoIn->setPosAt(0.80, QPointF(xOffset, Colors::contentStartY));
+    infoIn->setPosAt(0.90, QPointF(xOffset + 7, Colors::contentStartY));
+    infoIn->setPosAt(1.00, QPointF(xOffset, Colors::contentStartY));
+    movie_in->append(infoIn);
+
+    DemoItemAnimation *infoOut = new DemoItemAnimation(item, DemoItemAnimation::ANIM_OUT);
+    infoOut->timeline->setCurveShape(QTimeLine::EaseInCurve);
+    infoOut->setDuration(300);
+    infoOut->hideOnFinished = true;
+    infoOut->setStartPos(QPointF(xOffset, Colors::contentStartY));
+    infoOut->setPosAt(1.0, QPointF(-600, Colors::contentStartY));
+    movie_out->append(infoOut);
+}
+
+void MenuManager::createTicker()
+{
+    if (!Colors::noTicker){
+        Movie *movie_in = this->score->insertMovie("ticker");
+        Movie *movie_out = this->score->insertMovie("ticker -out");
+        Movie *movie_activate = this->score->insertMovie("ticker -activate");
+        Movie *movie_deactivate = this->score->insertMovie("ticker -deactivate");
+
+        this->ticker = new ItemCircleAnimation(this->window->scene, 0);
+        this->ticker->setZValue(50);
+        this->ticker->hide();
+
+        // Move ticker in:
+        int qtendpos = 485;
+        int qtPosY = 120;
+        this->tickerInAnim = new DemoItemAnimation(this->ticker, DemoItemAnimation::ANIM_IN);
+        this->tickerInAnim->setDuration(500);
+        this->tickerInAnim->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY + qtPosY));
+        this->tickerInAnim->setPosAt(0.60, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        this->tickerInAnim->setPosAt(0.70, QPointF(qtendpos + 30, Colors::contentStartY + qtPosY));
+        this->tickerInAnim->setPosAt(0.80, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        this->tickerInAnim->setPosAt(0.90, QPointF(qtendpos + 5, Colors::contentStartY + qtPosY));
+        this->tickerInAnim->setPosAt(1.00, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        movie_in->append(this->tickerInAnim);
+
+        // Move ticker out:
+        DemoItemAnimation *qtOut = new DemoItemAnimation(this->ticker, DemoItemAnimation::ANIM_OUT);
+        qtOut->hideOnFinished = true;
+        qtOut->setDuration(500);
+        qtOut->setStartPos(QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        qtOut->setPosAt(1.00, QPointF(this->window->scene->sceneRect().width() + 700, Colors::contentStartY + qtPosY));
+        movie_out->append(qtOut);
+
+        // Move ticker in on activate:
+        DemoItemAnimation *qtActivate = new DemoItemAnimation(this->ticker);
+        qtActivate->setDuration(400);
+        qtActivate->setStartPos(QPointF(this->window->scene->sceneRect().width(), Colors::contentStartY + qtPosY));
+        qtActivate->setPosAt(0.60, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        qtActivate->setPosAt(0.70, QPointF(qtendpos + 30, Colors::contentStartY + qtPosY));
+        qtActivate->setPosAt(0.80, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        qtActivate->setPosAt(0.90, QPointF(qtendpos + 5, Colors::contentStartY + qtPosY));
+        qtActivate->setPosAt(1.00, QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        movie_activate->append(qtActivate);
+
+        // Move ticker out on deactivate:
+        DemoItemAnimation *qtDeactivate = new DemoItemAnimation(this->ticker);
+        qtDeactivate->hideOnFinished = true;
+        qtDeactivate->setDuration(400);
+        qtDeactivate->setStartPos(QPointF(qtendpos, Colors::contentStartY + qtPosY));
+        qtDeactivate->setPosAt(1.00, QPointF(qtendpos, 800));
+        movie_deactivate->append(qtDeactivate);
+    }
+}
+
+void MenuManager::createUpnDownButtons()
+{
+    float xOffset = 15.0f;
+    float yOffset = 450.0f;
+
+    this->upButton = new TextButton("", TextButton::LEFT, MenuManager::UP, this->window->scene, 0, TextButton::UP);
+    this->upButton->prepare();
+    this->upButton->setPos(xOffset, yOffset);
+    this->upButton->setState(TextButton::DISABLED);
+
+    this->downButton = new TextButton("", TextButton::LEFT, MenuManager::DOWN, this->window->scene, 0, TextButton::DOWN);
+    this->downButton->prepare();
+    this->downButton->setPos(xOffset + 10 + this->downButton->sceneBoundingRect().width(), yOffset);
+
+    Movie *movieShake = this->score->insertMovie("upndown -shake");
+
+    DemoItemAnimation *shakeAnim = new DemoItemAnimation(this->upButton, DemoItemAnimation::ANIM_UNSPECIFIED);
+    shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
+    shakeAnim->setDuration(650);
+    shakeAnim->setStartPos(this->upButton->pos());
+    shakeAnim->setPosAt(0.60, this->upButton->pos());
+    shakeAnim->setPosAt(0.70, this->upButton->pos() + QPointF(-2, 0));
+    shakeAnim->setPosAt(0.80, this->upButton->pos() + QPointF(1, 0));
+    shakeAnim->setPosAt(0.90, this->upButton->pos() + QPointF(-1, 0));
+    shakeAnim->setPosAt(1.00, this->upButton->pos());
+    movieShake->append(shakeAnim);
+
+    shakeAnim = new DemoItemAnimation(this->downButton, DemoItemAnimation::ANIM_UNSPECIFIED);
+    shakeAnim->timeline->setCurveShape(QTimeLine::LinearCurve);
+    shakeAnim->setDuration(650);
+    shakeAnim->setStartPos(this->downButton->pos());
+    shakeAnim->setPosAt(0.60, this->downButton->pos());
+    shakeAnim->setPosAt(0.70, this->downButton->pos() + QPointF(-5, 0));
+    shakeAnim->setPosAt(0.80, this->downButton->pos() + QPointF(-3, 0));
+    shakeAnim->setPosAt(0.90, this->downButton->pos() + QPointF(-1, 0));
+    shakeAnim->setPosAt(1.00, this->downButton->pos());
+    movieShake->append(shakeAnim);
+}
+
+void MenuManager::createBackButton()
+{
+    Movie *backIn = this->score->insertMovie("back -in");
+    Movie *backOut = this->score->insertMovie("back -out");
+    Movie *backShake = this->score->insertMovie("back -shake");
+    createLowLeftButton(QLatin1String("Back"), ROOT, backIn, backOut, backShake, Colors::rootMenuName);
+}