launcher.cpp Example File
tools/qtdemo/launcher.cpp
/****************************************************************************
**
** Copyright (C) 2005-2006 Trolltech ASA. All rights reserved.
**
** This file is part of the documentation of the Qt Toolkit.
**
** This file may be used under the terms of the GNU General Public
** License version 2.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of
** this file. Please review the following information to ensure GNU
** General Public Licensing requirements will be met:
** http://www.trolltech.com/products/qt/opensource.html
**
** If you are unsure which license is appropriate for your use, please
** review the following information:
** http://www.trolltech.com/products/qt/licensing.html or contact the
** sales department at sales@trolltech.com.
**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/
#include <QtGui>
#include <QDomDocument>
#include <QtAssistant/QAssistantClient>
#include "displayshape.h"
#include "displaywidget.h"
#include "launcher.h"
Launcher::Launcher(QWidget *parent)
: QMainWindow(parent)
{
titleFont = font();
titleFont.setWeight(QFont::Bold);
buttonFont = font();
fontRatio = 0.8;
documentFont = font();
inFullScreenResize = false;
currentCategory = "[starting]";
QAction *parentPageAction1 = new QAction(tr("Show Parent Page"), this);
QAction *parentPageAction2 = new QAction(tr("Show Parent Page"), this);
QAction *parentPageAction3 = new QAction(tr("Show Parent Page"), this);
parentPageAction1->setShortcut(QKeySequence(tr("Escape")));
parentPageAction2->setShortcut(QKeySequence(tr("Backspace")));
parentPageAction3->setShortcut(QKeySequence(tr("Alt+Left")));
QAction *fullScreenAction = new QAction(tr("Toggle &Full Screen"), this);
fullScreenAction->setShortcut(QKeySequence(tr("Ctrl+F")));
QAction *exitAction = new QAction(tr("E&xit"), this);
exitAction->setShortcut(QKeySequence(tr("Ctrl+Q")));
connect(parentPageAction1, SIGNAL(triggered()), this, SIGNAL(showPage()));
connect(parentPageAction2, SIGNAL(triggered()), this, SIGNAL(showPage()));
connect(parentPageAction3, SIGNAL(triggered()), this, SIGNAL(showPage()));
connect(fullScreenAction, SIGNAL(triggered()),
this, SLOT(toggleFullScreen()));
connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
display = new DisplayWidget;
addAction(parentPageAction1);
addAction(parentPageAction2);
addAction(parentPageAction3);
addAction(fullScreenAction);
addAction(exitAction);
slideshowTimer = new QTimer(this);
slideshowTimer->setInterval(5000);
resizeTimer = new QTimer(this);
resizeTimer->setSingleShot(true);
connect(resizeTimer, SIGNAL(timeout()), this, SLOT(redisplayWindow()));
assistant = new QAssistantClient("assistant", this);
connect(display, SIGNAL(actionRequested(const QString &)),
this, SLOT(executeAction(const QString &)));
connect(display, SIGNAL(categoryRequested(const QString &)),
this, SLOT(showExamples(const QString &)));
connect(display, SIGNAL(documentationRequested(const QString &)),
this, SLOT(showExampleDocumentation(const QString &)));
connect(display, SIGNAL(exampleRequested(const QString &)),
this, SLOT(showExampleSummary(const QString &)));
connect(display, SIGNAL(launchRequested(const QString &)),
this, SLOT(launchExample(const QString &)));
connect(this, SIGNAL(showPage()), this, SLOT(showParentPage()),
Qt::QueuedConnection);
connect(this, SIGNAL(windowResized()), this, SLOT(redisplayWindow()),
Qt::QueuedConnection);
setCentralWidget(display);
setMaximumSize(QApplication::desktop()->screenGeometry().size());
setWindowTitle(tr("Qt Examples and Demos"));
setWindowIcon(QPixmap(":/images/qt4-logo.png"));
}
bool Launcher::setup()
{
documentationDir = QDir(QLibraryInfo::location(
QLibraryInfo::DocumentationPath));
if (!documentationDir.cd("html")) {
// Failed to find the HTML documentation.
// We can continue without it.
QMessageBox::warning(this, tr("No Documentation Found"),
tr("I could not find the Qt documentation."),
QMessageBox::Cancel, QMessageBox::NoButton);
}
imagesDir = documentationDir;
if (!imagesDir.cd("images")) {
// Failed to find the accompanying images for the documentation.
// We can continue without them.
QMessageBox::warning(this, tr("No Images Found"),
tr("I could not find any images for the Qt documentation."),
QMessageBox::Cancel, QMessageBox::NoButton);
}
maximumLabels = 0;
demosDir = QDir(QLibraryInfo::location(QLibraryInfo::DemosPath));
int demoCategories = readInfo(":/demos.xml", demosDir);
examplesDir = QDir(QLibraryInfo::location(QLibraryInfo::ExamplesPath));
int exampleCategories = readInfo(":/examples.xml", examplesDir);
if (demoCategories + exampleCategories <= 0) {
// Failed to find the examples.
QMessageBox::warning(this, tr("No Examples or Demos found"),
tr("I could not find any Qt examples or demos.\n"
"Please ensure that Qt is installed correctly."),
QMessageBox::Cancel, QMessageBox::NoButton);
return false;
}
maximumLabels = qMax(demoCategories + exampleCategories, maximumLabels);
// For example menus, remember that the menu has to include a Back button.
foreach (QString category, categories)
maximumLabels = qMax(examples[category].size() + 1, maximumLabels);
QString mainDescription = categoryDescriptions["[main]"];
if (!mainDescription.isEmpty())
mainDescription += tr("\n");
categoryDescriptions["[main]"] = mainDescription + tr(
"<p>Press <b>Escape</b>, <b>Backspace</b>, or <b>%1</b> to "
"return to a previous menu.</p>\n"
"<p>Press <b>%2</b> to switch between normal and full screen "
"modes.</p>\n"
"<p>Use <b>%3</b> to exit the launcher.</p>").arg(QString(
QKeySequence(tr("Alt+Left")))).arg(QString(
QKeySequence(tr("Ctrl+F")))).arg(QString(
QKeySequence(tr("Ctrl+Q"))));
emit showPage();
return true;
}
void Launcher::findDescriptionAndImages(const QString &uniqueName,
const QString &docName)
{
if (documentationDir.exists(docName)) {
exampleDetails[uniqueName]["document path"] = \
documentationDir.absoluteFilePath(docName);
QDomDocument exampleDoc;
QFile exampleFile(exampleDetails[uniqueName]["document path"]);
exampleDoc.setContent(&exampleFile);
QDomNodeList paragraphs = exampleDoc.elementsByTagName("p");
QString description;
for (int p = 0; p < int(paragraphs.length()); ++p) {
QDomNode descriptionNode = paragraphs.item(p);
description = readExampleDescription(descriptionNode);
if (description.indexOf(QRegExp(QString(
"((The|This) )?(%1 )?.*(example|demo)").arg(
exampleDetails[uniqueName]["name"]),
Qt::CaseInsensitive)) != -1) {
exampleDetails[uniqueName]["description"] = description;
break;
}
}
QDomNodeList images = exampleDoc.elementsByTagName("img");
QStringList imageFiles;
for (int i = 0; i < int(images.length()); ++i) {
QDomElement imageElement = images.item(i).toElement();
QString source = imageElement.attribute("src");
if (!source.contains("-logo"))
imageFiles.append(documentationDir.absoluteFilePath(source));
}
if (imageFiles.size() > 0)
imagePaths[uniqueName] = imageFiles;
}
}
int Launcher::readInfo(const QString &resource, const QDir &dir)
{
QFile categoriesFile(resource);
QDomDocument document;
document.setContent(&categoriesFile);
QDomElement documentElement = document.documentElement();
QDomNodeList categoryNodes = documentElement.elementsByTagName("category");
readCategoryDescription(dir, "[main]");
qtLogo.load(imagesDir.absoluteFilePath(":/images/qt4-logo.png"));
trolltechLogo.load(imagesDir.absoluteFilePath(":/images/trolltech-logo.png"));
for (int i = 0; i < int(categoryNodes.length()); ++i) {
QDomNode categoryNode = categoryNodes.item(i);
QDomElement element = categoryNode.toElement();
QString categoryName = element.attribute("name");
QString categoryDirName = element.attribute("dirname");
QString categoryDocName = element.attribute("docname");
QString categoryColor = element.attribute("color", "#f0f0f0");
QDir categoryDir = dir;
if (categoryDir.cd(categoryDirName)) {
readCategoryDescription(categoryDir, categoryName);
examples[categoryName] = QStringList();
QDomNodeList exampleNodes = element.elementsByTagName("example");
maximumLabels = qMax(maximumLabels, int(exampleNodes.length()));
for (int j = 0; j < int(exampleNodes.length()); ++j) {
QDir exampleDir = categoryDir;
QDomNode exampleNode = exampleNodes.item(j);
element = exampleNode.toElement();
QString exampleName = element.attribute("name");
QString exampleFileName = element.attribute("filename");
QString exampleDirName = element.attribute("dirname");
examples[categoryName].append(exampleName);
QString uniqueName = categoryName+"-"+exampleName;
exampleOptions[uniqueName] = QMap<QString,QString>();
exampleDetails[uniqueName] = QMap<QString,QString>();
QString docName;
if (!categoryDocName.isEmpty())
docName = categoryDocName+"-"+exampleFileName+".html";
else
docName = categoryDirName+"-"+exampleFileName+".html";
exampleDetails[uniqueName]["name"] = exampleName;
findDescriptionAndImages(uniqueName, docName);
exampleOptions[uniqueName]["changedirectory"] = element.attribute("changedirectory", "true");
exampleOptions[uniqueName]["color"] = element.attribute("color", "#f0f0f0");
if (!exampleDirName.isEmpty() && !exampleDir.cd(exampleDirName))
continue;
if (element.attribute("executable", "true") != "true")
continue;
if (exampleDir.cd(exampleFileName)) {
QString examplePath = findExecutable(exampleDir);
if (!examplePath.isNull()) {
exampleDetails[uniqueName]["absolute path"] = exampleDir.absolutePath();
exampleDetails[uniqueName]["path"] = examplePath;
}
}
}
categories.append(categoryName);
categoryColors[categoryName] = categoryColor;
}
}
return categories.size();
}
QString Launcher::findExecutable(const QDir &dir) const
{
QDir parentDir = dir;
parentDir.cdUp();
QFileInfo releaseDir(dir, "release");
if (releaseDir.isDir()) {
QDir currentDir(releaseDir.absoluteFilePath());
QString path = findExecutable(currentDir);
if (!path.isEmpty())
return path;
}
foreach (QFileInfo info, dir.entryInfoList(QDir::Dirs)) {
if (info.fileName().endsWith(".app"))
return info.absoluteFilePath();
QDir currentDir(info.absoluteFilePath());
if (currentDir != dir && currentDir != parentDir) {
QString path = findExecutable(currentDir);
if (!path.isNull())
return path;
}
}
foreach (QFileInfo info, dir.entryInfoList(QDir::Files)) {
if (info.isExecutable())
return info.absoluteFilePath();
}
return QString();
}
void Launcher::readCategoryDescription(const QDir &categoryDir,
const QString &categoryName)
{
if (categoryDir.exists("README")) {
QFile file(categoryDir.absoluteFilePath("README"));
if (!file.open(QFile::ReadOnly))
return;
QTextStream inputStream(&file);
QStringList paragraphs;
QStringList currentPara;
bool openQuote = true;
while (!inputStream.atEnd()) {
QString line = inputStream.readLine();
int at = 0;
while ((at = line.indexOf("\"", at)) != -1) {
if (openQuote)
line[at] = QChar::Punctuation_InitialQuote;
else
line[at] = QChar::Punctuation_FinalQuote;
openQuote = !openQuote;
}
if (!line.trimmed().isEmpty()) {
currentPara.append(line.trimmed());
} else if (!currentPara.isEmpty()) {
paragraphs.append(currentPara.join(" "));
currentPara.clear();
} else
break;
}
if (!currentPara.isEmpty())
paragraphs.append(currentPara.join(" "));
categoryDescriptions[categoryName] = "<p>" + \
paragraphs.join("\n</p><p>") + "</p>\n";
}
}
QString Launcher::readExampleDescription(const QDomNode &parentNode) const
{
QString description;
QDomNode node = parentNode.firstChild();
while (!node.isNull()) {
QString beginTag;
QString endTag;
if (node.isText())
description += node.nodeValue();
else if (node.hasChildNodes()) {
if (node.nodeName() == "b") {
beginTag = "<b>";
endTag = "</b>";
} else if (node.nodeName() == "a") {
beginTag = "<font color=\"blue\">";
endTag = "</font>";
} else if (node.nodeName() == "i") {
beginTag = "<i>";
endTag = "</i>";
} else if (node.nodeName() == "tt") {
beginTag = "<tt>";
endTag = "</tt>";
}
description += beginTag + readExampleDescription(node) + endTag;
}
node = node.nextSibling();
}
return description;
}
void Launcher::launchExample(const QString &uniqueName)
{
if (runningExamples.contains(uniqueName))
return;
QProcess *process = new QProcess(this);
connect(process, SIGNAL(finished(int)), this, SLOT(enableLaunching()));
#ifdef Q_OS_WIN
//make sure it finds the dlls on windows
QString curpath = QString::fromLocal8Bit(qgetenv("PATH").constData());
QString newpath = QString("PATH=%1;%2").arg(
QLibraryInfo::location(QLibraryInfo::BinariesPath), curpath);
process->setEnvironment(QStringList(newpath));
#endif
runningExamples.append(uniqueName);
runningProcesses[process] = uniqueName;
if (exampleOptions[uniqueName]["changedirectory"] == "true")
process->setWorkingDirectory(exampleDetails[uniqueName]["absolute path"]);
process->start(exampleDetails[uniqueName]["path"]);
if (process->state() == QProcess::Starting)
slideshowTimer->stop();
}
void Launcher::enableLaunching()
{
QProcess *process = static_cast<QProcess*>(sender());
QString example = runningProcesses.take(process);
process->deleteLater();
runningExamples.removeAll(example);
if (example == currentExample) {
for (int i = 0; i < display->shapesCount(); ++i) {
DisplayShape *shape = display->shape(i);
if (shape->metaData("launch").toString() == example) {
shape->setMetaData("fade", 15);
display->enableUpdates();
}
}
slideshowTimer->start();
}
}
void Launcher::executeAction(const QString &action)
{
if (action == "parent")
showParentPage();
else if (action == "exit") {
if (runningExamples.size() == 0) {
connect(display, SIGNAL(displayEmpty()), this, SLOT(close()));
display->reset();
} else
close();
}
}
void Launcher::closeEvent(QCloseEvent *event)
{
if (runningExamples.size() > 0) {
if (QMessageBox::warning(this, tr("Examples Running"),
tr("There are examples running. Do you really want to exit?"),
QMessageBox::Yes, QMessageBox::No) == QMessageBox::No)
event->ignore();
return;
}
foreach (QProcess *example, runningProcesses.keys()) {
example->terminate();
example->waitForFinished(1000);
}
qDeleteAll(runningProcesses.keys());
resizeTimer->stop();
slideshowTimer->stop();
}
void Launcher::showParentPage()
{
slideshowTimer->stop();
disconnect(slideshowTimer, SIGNAL(timeout()), this, 0);
if (!currentExample.isEmpty()) {
currentExample = "";
redisplayWindow();
} else if (!currentCategory.isEmpty()) {
currentCategory = "";
redisplayWindow();
}
}
void Launcher::newPage()
{
slideshowTimer->stop();
disconnect(slideshowTimer, SIGNAL(timeout()), this, 0);
disconnect(display, SIGNAL(displayEmpty()), this, 0);
}
DisplayShape *Launcher::addTitle(const QString &title, qreal verticalMargin)
{
QPointF titlePosition = QPointF(0.0, 2*verticalMargin);
DisplayShape *newTitle = new TitleShape(title, titleFont,
QPen(Qt::white), titlePosition,
QSizeF(0.5 * width(), 2*verticalMargin),
Qt::AlignHCenter | Qt::AlignTop);
newTitle->setPosition(QPointF(-newTitle->rect().width(), titlePosition.y()));
newTitle->setTarget(QPointF(0.25*width(), titlePosition.y()));
newTitle->setMetaData("fade", 15);
display->appendShape(newTitle);
return newTitle;
}
DisplayShape *Launcher::addTitleBackground(DisplayShape *titleShape)
{
QPainterPath backgroundPath;
backgroundPath.addRect(0, -titleShape->rect().height()*0.3,
width(), titleShape->rect().height()*1.6);
DisplayShape *titleBackground = new PanelShape(backgroundPath,
QBrush(QColor("#a6ce39")), QBrush(QColor("#a6ce39")), Qt::NoPen,
QPointF(width(), titleShape->position().y()),
backgroundPath.boundingRect().size());
titleBackground->setTarget(QPointF(0.0, titleShape->position().y()));
display->insertShape(0, titleBackground);
return titleBackground;
}
void Launcher::addVersionAndCopyright(const QRectF &rect)
{
DisplayShape *versionCaption = new TitleShape(
QString("Qt %1").arg(QT_VERSION_STR), font(),
QPen(QColor(0,0,0,0)),
QPointF(rect.center().x(), rect.top()),
QSizeF(0.5*rect.width(), rect.height()),
Qt::AlignRight | Qt::AlignVCenter);
versionCaption->setMetaData("fade", 15);
display->appendShape(versionCaption);
DisplayShape *copyrightCaption = new TitleShape(
QString("Copyright \xa9 2005-2006 Trolltech ASA"), font(),
QPen(QColor(0,0,0,0)),
rect.topLeft(), QSizeF(0.5*rect.width(), rect.height()),
Qt::AlignLeft | Qt::AlignVCenter);
copyrightCaption->setMetaData("fade", 15);
display->appendShape(copyrightCaption);
}
void Launcher::fadeShapes()
{
for (int i = 0; i < display->shapesCount(); ++i) {
DisplayShape *shape = display->shape(i);
shape->setMetaData("fade", -15);
shape->setMetaData("fade minimum", 0);
}
}
void Launcher::showCategories()
{
newPage();
fadeShapes();
currentCategory = "";
currentExample = "";
qreal horizontalMargin = 0.025*width();
qreal verticalMargin = 0.025*height();
DisplayShape *title = new TitleShape(tr("Qt Examples and Demos"),
titleFont, QPen(QColor("#a6ce39")), QPointF(),
QSizeF(0.5*width(), 4*verticalMargin));
title->setPosition(QPointF(width()/2 - title->rect().width()/2,
-title->rect().height()));
title->setTarget(QPointF(title->position().x(), verticalMargin));
display->appendShape(title);
qreal topMargin = 6*verticalMargin;
qreal bottomMargin = height() - 3.2*verticalMargin;
qreal space = bottomMargin - topMargin;
qreal step = qMin(title->rect().height() / fontRatio,
space/qreal(maximumLabels));
qreal textHeight = fontRatio * step;
QPointF startPosition = QPointF(0.0, topMargin);
QSizeF maxSize(10.8*horizontalMargin, textHeight);
qreal maxWidth = 0.0;
QList<DisplayShape*> newShapes;
foreach (QString category, categories) {
DisplayShape *caption = new TitleShape(category, font(), QPen(),
startPosition, maxSize);
caption->setPosition(QPointF(-caption->rect().width(),
caption->position().y()));
caption->setTarget(QPointF(2*horizontalMargin, caption->position().y()));
newShapes.append(caption);
startPosition += QPointF(0.0, step);
maxWidth = qMax(maxWidth, caption->rect().width());
}
DisplayShape *exitButton = new TitleShape(tr("Exit"), font(),
QPen(Qt::white), startPosition, maxSize);
exitButton->setTarget(QPointF(2*horizontalMargin, exitButton->position().y()));
newShapes.append(exitButton);
startPosition = QPointF(width(), topMargin);
qreal extra = (step - textHeight)/4;
QPainterPath backgroundPath;
backgroundPath.addRect(-2*extra, -extra, maxWidth + 4*extra, textHeight + 2*extra);
foreach (QString category, categories) {
DisplayShape *background = new PanelShape(backgroundPath,
QBrush(categoryColors[category]), QBrush(QColor("#e0e0ff")),
Qt::NoPen, startPosition,
QSizeF(maxWidth + 4*extra, textHeight + 2*extra));
background->setMetaData("category", category);
background->setInteractive(true);
background->setTarget(QPointF(2*horizontalMargin,
background->position().y()));
display->insertShape(0, background);
startPosition += QPointF(0.0, step);
}
QPainterPath exitPath;
exitPath.moveTo(-2*extra, -extra);
exitPath.lineTo(-8*extra, textHeight/2);
exitPath.lineTo(-extra, textHeight + extra);
exitPath.lineTo(maxWidth + 2*extra, textHeight + extra);
exitPath.lineTo(maxWidth + 2*extra, -extra);
exitPath.closeSubpath();
DisplayShape *exitBackground = new PanelShape(exitPath,
QBrush(QColor("#a6ce39")), QBrush(QColor("#c7f745")), Qt::NoPen,
startPosition, QSizeF(maxWidth + 10*extra, textHeight + 2*extra));
exitBackground->setMetaData("action", "exit");
exitBackground->setInteractive(true);
exitBackground->setTarget(QPointF(2*horizontalMargin,
exitBackground->position().y()));
display->insertShape(0, exitBackground);
foreach (DisplayShape *caption, newShapes) {
QPointF position = caption->target();
QSizeF size = caption->rect().size();
caption->setPosition(QPointF(-maxWidth, position.y()));
display->appendShape(caption);
}
qreal leftMargin = 3*horizontalMargin + maxWidth;
qreal rightMargin = width() - 3*horizontalMargin;
DocumentShape *description = new DocumentShape(categoryDescriptions["[main]"],
documentFont, QPointF(leftMargin, topMargin),
QSizeF(rightMargin - leftMargin, space), 0);
description->setMetaData("fade", 10);
display->appendShape(description);
qreal imageHeight = title->rect().height() + verticalMargin;
qreal qtLength = qMin(imageHeight, title->rect().left()-3*horizontalMargin);
QSizeF qtMaxSize = QSizeF(qtLength, qtLength);
DisplayShape *qtShape = new ImageShape(qtLogo,
QPointF(2*horizontalMargin-extra, -imageHeight), qtMaxSize, 0,
Qt::AlignLeft | Qt::AlignVCenter);
qtShape->setMetaData("fade", 15);
qtShape->setTarget(QPointF(qtShape->rect().x(), verticalMargin));
display->insertShape(0, qtShape);
QSizeF trolltechMaxSize = QSizeF(
width()-3*horizontalMargin-title->rect().right(), imageHeight);
DisplayShape *trolltechShape = new ImageShape(trolltechLogo,
QPointF(width()-2*horizontalMargin-trolltechMaxSize.width()+extra,
-imageHeight),
trolltechMaxSize, 0, Qt::AlignRight | Qt::AlignVCenter);
trolltechShape->setMetaData("fade", 15);
trolltechShape->setTarget(QPointF(trolltechShape->rect().x(),
verticalMargin));
display->insertShape(0, trolltechShape);
addVersionAndCopyright(QRectF(2*horizontalMargin,
height() - verticalMargin - textHeight,
width()-4*horizontalMargin, textHeight));
}
void Launcher::showExamples(const QString &category)
{
newPage();
fadeShapes();
currentCategory = category;
currentExample = "";
qreal horizontalMargin = 0.025*width();
qreal verticalMargin = 0.025*height();
DisplayShape *newTitle = addTitle(category, verticalMargin);
addTitleBackground(newTitle);
qreal topMargin = 6*verticalMargin;
qreal bottomMargin = height() - 3.2*verticalMargin;
qreal space = bottomMargin - topMargin;
qreal step = qMin(newTitle->rect().height() / fontRatio,
space/qreal(maximumLabels));
qreal textHeight = fontRatio * step;
QPointF startPosition = QPointF(2*horizontalMargin, height() + topMargin);
QPointF finishPosition = QPointF(2*horizontalMargin, topMargin);
QSizeF maxSize(32*horizontalMargin, textHeight);
qreal maxWidth = 0.0;
foreach (QString example, examples[currentCategory]) {
DisplayShape *caption = new TitleShape(example, font(), QPen(),
startPosition, maxSize);
caption->setTarget(finishPosition);
display->appendShape(caption);
startPosition += QPointF(0.0, step);
finishPosition += QPointF(0.0, step);
maxWidth = qMax(maxWidth, caption->rect().width());
}
DisplayShape *menuButton = new TitleShape(tr("Main Menu"), font(),
QPen(Qt::white), startPosition, maxSize);
menuButton->setTarget(finishPosition);
display->appendShape(menuButton);
maxWidth = qMax(maxWidth, menuButton->rect().width());
startPosition = QPointF(width(), topMargin);
qreal extra = (step - textHeight)/4;
foreach (QString example, examples[currentCategory]) {
QString uniqueName = currentCategory+"-"+example;
QPainterPath path;
path.addRect(-2*extra, -extra, maxWidth + 4*extra, textHeight + 2*extra);
DisplayShape *background = new PanelShape(path,
QBrush(QColor(exampleOptions[uniqueName]["color"])),
QBrush(QColor("#e0e0ff")),
Qt::NoPen, startPosition,
QSizeF(maxWidth + 4*extra, textHeight + 2*extra));
background->setMetaData("example", uniqueName);
background->setInteractive(true);
background->setTarget(QPointF(2*horizontalMargin,
background->position().y()));
display->insertShape(0, background);
startPosition += QPointF(0.0, step);
}
QPainterPath backPath;
backPath.moveTo(-2*extra, -extra);
backPath.lineTo(-8*extra, textHeight/2);
backPath.lineTo(-extra, textHeight + extra);
backPath.lineTo(maxWidth + 2*extra, textHeight + extra);
backPath.lineTo(maxWidth + 2*extra, -extra);
backPath.closeSubpath();
DisplayShape *buttonBackground = new PanelShape(backPath,
QBrush(QColor("#a6ce39")), QBrush(QColor("#c7f745")), Qt::NoPen,
startPosition, QSizeF(maxWidth + 10*extra, textHeight + 2*extra));
buttonBackground->setMetaData("action", "parent");
buttonBackground->setInteractive(true);
buttonBackground->setTarget(QPointF(2*horizontalMargin,
buttonBackground->position().y()));
display->insertShape(0, buttonBackground);
qreal leftMargin = 3*horizontalMargin + maxWidth;
qreal rightMargin = width() - 3*horizontalMargin;
DocumentShape *description = new DocumentShape(
categoryDescriptions[currentCategory], documentFont,
QPointF(leftMargin, topMargin), QSizeF(rightMargin - leftMargin, space),
0);
description->setMetaData("fade", 10);
display->appendShape(description);
addVersionAndCopyright(QRectF(2*horizontalMargin,
height() - verticalMargin - textHeight,
width()-4*horizontalMargin, textHeight));
}
void Launcher::showExampleDocumentation(const QString &uniqueName)
{
disconnect(display, SIGNAL(displayEmpty()), this, 0);
currentExample = uniqueName;
assistant->showPage(exampleDetails[uniqueName]["document path"]);
}
void Launcher::showExampleSummary(const QString &uniqueName)
{
newPage();
fadeShapes();
currentExample = uniqueName;
qreal horizontalMargin = 0.025*width();
qreal verticalMargin = 0.025*height();
DisplayShape *newTitle = addTitle(exampleDetails[currentExample]["name"],
verticalMargin);
DisplayShape *titleBackground = addTitleBackground(newTitle);
qreal topMargin = 2*verticalMargin + titleBackground->rect().bottom();
qreal bottomMargin = height() - 8*verticalMargin;
qreal space = bottomMargin - topMargin;
qreal step = qMin(newTitle->rect().height() / fontRatio,
(bottomMargin + qreal(4.8)*verticalMargin - topMargin)
/qreal(maximumLabels));
qreal textHeight = fontRatio * step;
qreal leftMargin = 3*horizontalMargin;
qreal rightMargin = width() - 3*horizontalMargin;
if (exampleDetails[currentExample].contains("description")) {
DocumentShape *description = new DocumentShape(
exampleDetails[currentExample]["description"], documentFont,
QPointF(leftMargin, topMargin),
QSizeF(rightMargin-leftMargin, space), 0);
description->setMetaData("fade", 10);
description->setPosition(QPointF(description->position().x(),
0.8*height() - description->rect().height()));
display->appendShape(description);
space = description->position().y() - topMargin - 2*verticalMargin;
}
if (imagePaths.contains(currentExample)) {
QImage image(imagePaths[currentExample][0]);
QSizeF imageMaxSize = QSizeF(width() - 8*horizontalMargin, space);
currentFrame = new ImageShape(image,
QPointF(width() - imageMaxSize.width()/2, topMargin),
imageMaxSize);
currentFrame->setMetaData("fade", 15);
currentFrame->setTarget(QPointF(width()/2 - imageMaxSize.width()/2,
topMargin));
display->appendShape(currentFrame);
if (imagePaths[currentExample].size() > 1) {
connect(slideshowTimer, SIGNAL(timeout()),
this, SLOT(updateExampleSummary()));
slideshowFrame = 0;
slideshowTimer->start();
}
}
QSizeF maxSize(0.3 * width(), 2*verticalMargin);
leftMargin = 0.0;
rightMargin = 0.0;
if (true) {
DisplayShape *backButton = new TitleShape(currentCategory, font(),
QPen(Qt::white), QPointF(0.1*width(), height()), maxSize,
Qt::AlignLeft | Qt::AlignTop);
backButton->setTarget(QPointF(backButton->position().x(),
height() - 5.2*verticalMargin));
display->appendShape(backButton);
qreal maxWidth = backButton->rect().width();
qreal textHeight = backButton->rect().height();
qreal extra = (3*verticalMargin - textHeight)/4;
QPainterPath path;
path.moveTo(-extra, -extra);
path.lineTo(-4*extra, textHeight/2);
path.lineTo(-extra, textHeight + extra);
path.lineTo(maxWidth + 2*extra, textHeight + extra);
path.lineTo(maxWidth + 2*extra, -extra);
path.closeSubpath();
DisplayShape *buttonBackground = new PanelShape(path,
QBrush(QColor("#a6ce39")), QBrush(QColor("#c7f745")), Qt::NoPen,
backButton->position(),
QSizeF(maxWidth + 6*extra, textHeight + 2*extra));
buttonBackground->setMetaData("category", currentCategory);
buttonBackground->setInteractive(true);
buttonBackground->setTarget(backButton->target());
display->insertShape(0, buttonBackground);
leftMargin = buttonBackground->rect().right();
}
if (exampleDetails[currentExample].contains("absolute path")) {
DisplayShape *launchCaption = new TitleShape(tr("Launch"),
font(), QPen(Qt::white), QPointF(0.0, 0.0), maxSize,
Qt::AlignLeft | Qt::AlignTop);
launchCaption->setPosition(QPointF(
0.9*width() - launchCaption->rect().width(), height()));
launchCaption->setTarget(QPointF(launchCaption->position().x(),
height() - 5.2*verticalMargin));
display->appendShape(launchCaption);
qreal maxWidth = launchCaption->rect().width();
qreal textHeight = launchCaption->rect().height();
qreal extra = (3*verticalMargin - textHeight)/4;
QPainterPath path;
path.addRect(-2*extra, -extra, maxWidth + 4*extra, textHeight + 2*extra);
QColor backgroundColor = QColor("#a63e39");
QColor highlightedColor = QColor("#f95e56");
DisplayShape *background = new PanelShape(path,
QBrush(backgroundColor), QBrush(highlightedColor), Qt::NoPen,
launchCaption->position(),
QSizeF(maxWidth + 4*extra, textHeight + 2*extra));
background->setMetaData("fade minimum", 120);
background->setMetaData("launch", currentExample);
background->setInteractive(true);
background->setTarget(launchCaption->target());
if (runningExamples.contains(currentExample)) {
background->setMetaData("highlight", true);
background->setMetaData("highlight scale", 0.99);
background->animate();
background->setMetaData("fade", -135);
slideshowTimer->stop();
}
display->insertShape(0, background);
rightMargin = background->rect().left();
}
if (exampleDetails[currentExample].contains("document path")) {
DisplayShape *documentCaption = new TitleShape(tr("Show Documentation"),
font(), QPen(Qt::white), QPointF(0.0, 0.0), maxSize,
Qt::AlignLeft | Qt::AlignTop);
if (rightMargin == 0.0) {
documentCaption->setPosition(QPointF(
0.9*width() - documentCaption->rect().width(), height()));
} else {
documentCaption->setPosition(QPointF(
leftMargin/2 + rightMargin/2 - documentCaption->rect().width()/2,
height()));
}
documentCaption->setTarget(QPointF(documentCaption->position().x(),
height() - 5.2*verticalMargin));
display->appendShape(documentCaption);
qreal maxWidth = documentCaption->rect().width();
qreal textHeight = documentCaption->rect().height();
qreal extra = (3*verticalMargin - textHeight)/4;
QPainterPath path;
path.addRect(-2*extra, -extra, maxWidth + 4*extra, textHeight + 2*extra);
DisplayShape *background = new PanelShape(path,
QBrush(QColor("#9c9cff")), QBrush(QColor("#cfcfff")), Qt::NoPen,
documentCaption->position(),
QSizeF(maxWidth + 4*extra, textHeight + 2*extra));
background->setMetaData("fade minimum", 120);
background->setMetaData("documentation", currentExample);
background->setInteractive(true);
background->setTarget(documentCaption->target());
display->insertShape(0, background);
}
addVersionAndCopyright(QRectF(2*horizontalMargin,
height() - verticalMargin - textHeight,
width()-4*horizontalMargin, textHeight));
}
void Launcher::updateExampleSummary()
{
if (imagePaths.contains(currentExample)) {
currentFrame->setMetaData("fade", -15);
currentFrame->setTarget(currentFrame->position() - QPointF(0.5*width(),
0));
slideshowFrame = (slideshowFrame+1) % imagePaths[currentExample].size();
QImage image(imagePaths[currentExample][slideshowFrame]);
QSizeF imageSize = currentFrame->size();
QPointF imagePosition = QPointF(width() - imageSize.width()/2,
currentFrame->position().y());
currentFrame = new ImageShape(image, imagePosition, imageSize);
currentFrame->setMetaData("fade", 15);
currentFrame->setTarget(QPointF(width()/2 - imageSize.width()/2,
imagePosition.y()));
display->appendShape(currentFrame);
}
}
void Launcher::toggleFullScreen()
{
if (inFullScreenResize)
return;
inFullScreenResize = true;
connect(display, SIGNAL(displayEmpty()), this, SLOT(resizeWindow()),
Qt::QueuedConnection);
display->reset();
}
void Launcher::resizeWindow()
{
disconnect(display, SIGNAL(displayEmpty()), this, 0);
if (isFullScreen())
showNormal();
else
showFullScreen();
}
void Launcher::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
documentFont = font();
documentFont.setPointSizeF(qMin(documentFont.pointSizeF()*width()/640.0,
documentFont.pointSizeF()*height()/480.0));
if (inFullScreenResize)
inFullScreenResize = false;
if (currentCategory != "[starting]")
resizeTimer->start(500);
}
void Launcher::redisplayWindow()
{
if (!currentExample.isEmpty())
showExampleSummary(currentExample);
else if (!currentCategory.isEmpty())
showExamples(currentCategory);
else
showCategories();
}