From bb0465258d20badae7f9aa62849c02a94244570c Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Mon, 5 Oct 2009 19:21:44 +1000 Subject: Consistent Commenting in Samegame --- demos/declarative/samegame/content/samegame.js | 1 + 1 file changed, 1 insertion(+) diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index e42b7cc..cf55b59 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -30,6 +30,7 @@ function initBoard() board[i].destroy(); } + //Calculate board size maxX = Math.floor(gameCanvas.width/tileSize); maxY = Math.floor(gameCanvas.height/tileSize); maxIndex = maxY*maxX; -- cgit v0.12 From 9d2de4a1aa26b4a19a6ffb4dad7a2d8ad06163d9 Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Tue, 6 Oct 2009 13:33:05 +1000 Subject: Test icon() property. --- tests/auto/declarative/qfxwebview/data/basic.html | 2 +- tests/auto/declarative/qfxwebview/data/basic.png | Bin 0 -> 3961 bytes tests/auto/declarative/qfxwebview/tst_qfxwebview.cpp | 7 +++++-- 3 files changed, 6 insertions(+), 3 deletions(-) create mode 100644 tests/auto/declarative/qfxwebview/data/basic.png diff --git a/tests/auto/declarative/qfxwebview/data/basic.html b/tests/auto/declarative/qfxwebview/data/basic.html index 254317c..c262f12 100644 --- a/tests/auto/declarative/qfxwebview/data/basic.html +++ b/tests/auto/declarative/qfxwebview/data/basic.html @@ -1,6 +1,6 @@ Basic - + diff --git a/tests/auto/declarative/qfxwebview/data/basic.png b/tests/auto/declarative/qfxwebview/data/basic.png new file mode 100644 index 0000000..35717cc Binary files /dev/null and b/tests/auto/declarative/qfxwebview/data/basic.png differ diff --git a/tests/auto/declarative/qfxwebview/tst_qfxwebview.cpp b/tests/auto/declarative/qfxwebview/tst_qfxwebview.cpp index 834c07f..dc124ce 100644 --- a/tests/auto/declarative/qfxwebview/tst_qfxwebview.cpp +++ b/tests/auto/declarative/qfxwebview/tst_qfxwebview.cpp @@ -72,8 +72,8 @@ void tst_qfxwebview::testBasicProperties() QVERIFY(wv != 0); QTRY_COMPARE(wv->progress(), 1.0); QCOMPARE(wv->title(),QString("Basic")); - wv->icon().save("test.png"); - //QCOMPARE(wv->icon(),QPixmap(SRCDIR "/data/basic.ico")); + QTRY_COMPARE(wv->icon().width(), 48); + QCOMPARE(wv->icon(),QPixmap(SRCDIR "/data/basic.png")); QCOMPARE(wv->statusText(),QString("")); QFile htmlfile(SRCDIR "/data/basic.html"); QVERIFY(htmlfile.open(QIODevice::ReadOnly)); @@ -83,6 +83,9 @@ void tst_qfxwebview::testBasicProperties() expectedhtml.replace(QRegExp("\\s+"),""); QCOMPARE(actualhtml____,expectedhtml); // same, ignoring whitespace QCOMPARE(wv->width(), 123.0); + QCOMPARE(wv->webPageWidth(), 0); + QCOMPARE(wv->preferredWidth(), 0); + QCOMPARE(wv->zoomFactor(), 1.0); QCOMPARE(wv->url(), QUrl::fromLocalFile(SRCDIR "/data/basic.html")); QCOMPARE(wv->status(), QFxWebView::Ready); QVERIFY(wv->reloadAction()); -- cgit v0.12 From 1042b1e1930131750d54112ec8f3deb6f70a9c76 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 7 Oct 2009 10:49:27 +1000 Subject: Fix so items are stretched to width of viewer if viewer is resized; otherwise, shrink viewer to width of main canvas item. (Last fix did not work because usually items should resize with the viewer.) --- tools/qmlviewer/qmlviewer.cpp | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/tools/qmlviewer/qmlviewer.cpp b/tools/qmlviewer/qmlviewer.cpp index e185536..07b68ea 100644 --- a/tools/qmlviewer/qmlviewer.cpp +++ b/tools/qmlviewer/qmlviewer.cpp @@ -55,6 +55,26 @@ QT_BEGIN_NAMESPACE + +class SizedMenuBar : public QMenuBar +{ + Q_OBJECT +public: + SizedMenuBar(QWidget *parent, QWidget *referenceWidget) + : QMenuBar(parent), refWidget(referenceWidget) + { + } + + virtual QSize sizeHint() const + { + return QSize(refWidget->sizeHint().width(), QMenuBar::sizeHint().height()); + } + +private: + QWidget *refWidget; +}; + + class PreviewDeviceSkin : public DeviceSkin { Q_OBJECT @@ -281,10 +301,6 @@ QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags) } else { recdlg->warning->hide(); } - - - if (!(flags & Qt::FramelessWindowHint)) - createMenu(menuBar(),0); canvas = new QmlView(this); canvas->setAttribute(Qt::WA_OpaquePaintEvent); @@ -296,13 +312,16 @@ QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags) QObject::connect(canvas, SIGNAL(sceneResized(QSize)), this, SLOT(sceneResized(QSize))); QObject::connect(canvas, SIGNAL(errors(QList)), this, SLOT(executeErrors())); + if (!(flags & Qt::FramelessWindowHint)) + createMenu(menuBar(),0); + QVBoxLayout *layout = new QVBoxLayout; layout->setMargin(0); layout->setSpacing(0); setLayout(layout); if (mb) layout->addWidget(mb); - layout->addWidget(canvas, 0, Qt::AlignLeft); + layout->addWidget(canvas); setupProxy(); canvas->engine()->networkAccessManager()->setCookieJar(new PersistentCookieJar(this)); @@ -319,7 +338,7 @@ QmlViewer::QmlViewer(QWidget *parent, Qt::WindowFlags flags) QMenuBar *QmlViewer::menuBar() const { if (!mb) - mb = new QMenuBar((QWidget*)this); + mb = new SizedMenuBar((QWidget*)this, canvas); return mb; } @@ -650,8 +669,8 @@ void QmlViewer::openQml(const QString& fileName) if (!skin) { canvas->updateGeometry(); - canvas->resize(canvas->sizeHint()); - canvas->updateGeometry(); + if (mb) + mb->updateGeometry(); resize(sizeHint()); } else { if (scaleSkin) -- cgit v0.12 From e25009d28c58b3ff7541374475f8c2c278cef02e Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 7 Oct 2009 11:01:05 +1000 Subject: Refactor tileSize to the gameCanvas item --- demos/declarative/samegame/content/samegame.js | 25 ++++++++++++------------- demos/declarative/samegame/samegame.qml | 1 + 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/demos/declarative/samegame/content/samegame.js b/demos/declarative/samegame/content/samegame.js index cf55b59..ba2346f 100755 --- a/demos/declarative/samegame/content/samegame.js +++ b/demos/declarative/samegame/content/samegame.js @@ -1,8 +1,7 @@ /* This script file handles the game logic */ //Note that X/Y referred to here are in game coordinates -var maxX = 10;//Nums are for tileSize 40 +var maxX = 10;//Nums are for gameCanvas.tileSize 40 var maxY = 15; -var tileSize = 40; var maxIndex = maxX*maxY; var board = new Array(maxIndex); var tileSrc = "content/BoomBlock.qml"; @@ -31,8 +30,8 @@ function initBoard() } //Calculate board size - maxX = Math.floor(gameCanvas.width/tileSize); - maxY = Math.floor(gameCanvas.height/tileSize); + maxX = Math.floor(gameCanvas.width/gameCanvas.tileSize); + maxY = Math.floor(gameCanvas.height/gameCanvas.tileSize); maxIndex = maxY*maxX; //Close dialogs @@ -56,8 +55,8 @@ var floodBoard;//Set to 1 if the floodFill reaches off that node //NOTE: Be careful with vars named x,y, as the calling object's x,y are still in scope function handleClick(x,y) { - xIdx = Math.floor(x/tileSize); - yIdx = Math.floor(y/tileSize); + xIdx = Math.floor(x/gameCanvas.tileSize); + yIdx = Math.floor(y/gameCanvas.tileSize); if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) return; if(board[index(xIdx, yIdx)] == null) @@ -111,7 +110,7 @@ function shuffleDown() }else{ if(fallDist > 0){ obj = board[index(xIdx,yIdx)]; - obj.targetY += fallDist * tileSize; + obj.targetY += fallDist * gameCanvas.tileSize; board[index(xIdx,yIdx+fallDist)] = obj; board[index(xIdx,yIdx)] = null; } @@ -129,7 +128,7 @@ function shuffleDown() obj = board[index(xIdx,yIdx)]; if(obj == null) continue; - obj.targetX -= fallDist * tileSize; + obj.targetX -= fallDist * gameCanvas.tileSize; board[index(xIdx-fallDist,yIdx)] = obj; board[index(xIdx,yIdx)] = null; } @@ -188,11 +187,11 @@ function createBlock(xIdx,yIdx){ } dynamicObject.type = Math.floor(Math.random() * 3); dynamicObject.parent = gameCanvas; - dynamicObject.x = xIdx*tileSize; - dynamicObject.targetX = xIdx*tileSize; - dynamicObject.targetY = yIdx*tileSize; - dynamicObject.width = tileSize; - dynamicObject.height = tileSize; + dynamicObject.x = xIdx*gameCanvas.tileSize; + dynamicObject.targetX = xIdx*gameCanvas.tileSize; + dynamicObject.targetY = yIdx*gameCanvas.tileSize; + dynamicObject.width = gameCanvas.tileSize; + dynamicObject.height = gameCanvas.tileSize; dynamicObject.spawned = true; board[index(xIdx,yIdx)] = dynamicObject; }else{//isError or isLoading diff --git a/demos/declarative/samegame/samegame.qml b/demos/declarative/samegame/samegame.qml index 92d85f3..709f4e9 100644 --- a/demos/declarative/samegame/samegame.qml +++ b/demos/declarative/samegame/samegame.qml @@ -21,6 +21,7 @@ Rectangle { Item { id: gameCanvas property int score: 0 + property int tileSize: 40 z: 20; anchors.centerIn: parent width: parent.width - (parent.width % tileSize); -- cgit v0.12 From 95821d745a60e60422294dd718cbed5678ef5f1f Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 7 Oct 2009 11:03:21 +1000 Subject: Add SameGame based advanced tutorial Could use some cleanup, as I didn't manage to get code snippets working correctly. Also might benefit from being re-written by a good tutor. --- doc/src/declarative/advtutorial.qdoc | 18 ++ doc/src/declarative/advtutorial1.qdoc | 116 +++++++++++ doc/src/declarative/advtutorial2.qdoc | 113 +++++++++++ doc/src/declarative/advtutorial3.qdoc | 197 +++++++++++++++++++ doc/src/declarative/advtutorial4.qdoc | 120 ++++++++++++ doc/src/declarative/qtdeclarative.qdoc | 1 + .../tutorials/samegame/samegame1/Block.qml | 10 + .../tutorials/samegame/samegame1/Button.qml | 25 +++ .../samegame/samegame1/pics/background.png | Bin 0 -> 153328 bytes .../tutorials/samegame/samegame1/pics/redStone.png | Bin 0 -> 2604 bytes .../tutorials/samegame/samegame1/samegame.qml | 38 ++++ .../tutorials/samegame/samegame2/Block.qml | 10 + .../tutorials/samegame/samegame2/Button.qml | 25 +++ .../samegame/samegame2/pics/background.png | Bin 0 -> 153328 bytes .../tutorials/samegame/samegame2/pics/redStone.png | Bin 0 -> 2604 bytes .../tutorials/samegame/samegame2/samegame.js | 59 ++++++ .../tutorials/samegame/samegame2/samegame.qml | 39 ++++ .../tutorials/samegame/samegame3/Block.qml | 19 ++ .../tutorials/samegame/samegame3/Button.qml | 25 +++ .../tutorials/samegame/samegame3/Dialog.qml | 21 ++ .../samegame/samegame3/pics/background.png | Bin 0 -> 153328 bytes .../samegame/samegame3/pics/blueStone.png | Bin 0 -> 2691 bytes .../samegame/samegame3/pics/greenStone.png | Bin 0 -> 2662 bytes .../tutorials/samegame/samegame3/pics/redStone.png | Bin 0 -> 2604 bytes .../tutorials/samegame/samegame3/samegame.js | 185 ++++++++++++++++++ .../tutorials/samegame/samegame3/samegame.qml | 56 ++++++ .../tutorials/samegame/samegame4/README | 10 + .../samegame/samegame4/content/BoomBlock.qml | 54 +++++ .../samegame/samegame4/content/Button.qml | 25 +++ .../samegame/samegame4/content/Dialog.qml | 21 ++ .../samegame/samegame4/content/pics/background.png | Bin 0 -> 153328 bytes .../samegame/samegame4/content/pics/blueStar.png | Bin 0 -> 278 bytes .../samegame/samegame4/content/pics/blueStone.png | Bin 0 -> 2691 bytes .../samegame/samegame4/content/pics/greenStar.png | Bin 0 -> 273 bytes .../samegame/samegame4/content/pics/greenStone.png | Bin 0 -> 2662 bytes .../samegame/samegame4/content/pics/redStar.png | Bin 0 -> 274 bytes .../samegame/samegame4/content/pics/redStone.png | Bin 0 -> 2604 bytes .../samegame/samegame4/content/pics/star.png | Bin 0 -> 262 bytes .../samegame4/content/pics/yellowStone.png | Bin 0 -> 2667 bytes .../samegame/samegame4/content/samegame.js | 217 +++++++++++++++++++++ .../tutorials/samegame/samegame4/highscores/README | 1 + .../samegame/samegame4/highscores/score_data.xml | 2 + .../samegame/samegame4/highscores/score_style.xsl | 28 +++ .../samegame/samegame4/highscores/scores.php | 34 ++++ .../tutorials/samegame/samegame4/samegame.qml | 71 +++++++ 45 files changed, 1540 insertions(+) create mode 100644 doc/src/declarative/advtutorial.qdoc create mode 100644 doc/src/declarative/advtutorial1.qdoc create mode 100644 doc/src/declarative/advtutorial2.qdoc create mode 100644 doc/src/declarative/advtutorial3.qdoc create mode 100644 doc/src/declarative/advtutorial4.qdoc create mode 100644 examples/declarative/tutorials/samegame/samegame1/Block.qml create mode 100644 examples/declarative/tutorials/samegame/samegame1/Button.qml create mode 100644 examples/declarative/tutorials/samegame/samegame1/pics/background.png create mode 100644 examples/declarative/tutorials/samegame/samegame1/pics/redStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame1/samegame.qml create mode 100644 examples/declarative/tutorials/samegame/samegame2/Block.qml create mode 100644 examples/declarative/tutorials/samegame/samegame2/Button.qml create mode 100644 examples/declarative/tutorials/samegame/samegame2/pics/background.png create mode 100644 examples/declarative/tutorials/samegame/samegame2/pics/redStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame2/samegame.js create mode 100644 examples/declarative/tutorials/samegame/samegame2/samegame.qml create mode 100644 examples/declarative/tutorials/samegame/samegame3/Block.qml create mode 100644 examples/declarative/tutorials/samegame/samegame3/Button.qml create mode 100644 examples/declarative/tutorials/samegame/samegame3/Dialog.qml create mode 100644 examples/declarative/tutorials/samegame/samegame3/pics/background.png create mode 100644 examples/declarative/tutorials/samegame/samegame3/pics/blueStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame3/pics/greenStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame3/pics/redStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame3/samegame.js create mode 100644 examples/declarative/tutorials/samegame/samegame3/samegame.qml create mode 100644 examples/declarative/tutorials/samegame/samegame4/README create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/Button.qml create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/Dialog.qml create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/background.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/blueStar.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/blueStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/greenStar.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/greenStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/redStar.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/redStone.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/star.png create mode 100644 examples/declarative/tutorials/samegame/samegame4/content/pics/yellowStone.png create mode 100755 examples/declarative/tutorials/samegame/samegame4/content/samegame.js create mode 100644 examples/declarative/tutorials/samegame/samegame4/highscores/README create mode 100755 examples/declarative/tutorials/samegame/samegame4/highscores/score_data.xml create mode 100755 examples/declarative/tutorials/samegame/samegame4/highscores/score_style.xsl create mode 100755 examples/declarative/tutorials/samegame/samegame4/highscores/scores.php create mode 100644 examples/declarative/tutorials/samegame/samegame4/samegame.qml diff --git a/doc/src/declarative/advtutorial.qdoc b/doc/src/declarative/advtutorial.qdoc new file mode 100644 index 0000000..c8075de --- /dev/null +++ b/doc/src/declarative/advtutorial.qdoc @@ -0,0 +1,18 @@ +/*! +\page advtutorial.html +\title Advanced Tutorial + +This tutorial goes step-by-step through creating a full application using just QML. It is assumed that you already know basic QML (such as from doing the simple tutorial) and the focus is on showing how to turn that knowledge into a complete and functioning application. + +In this tutorial we recreate, step by step, the Same Game demo in $QTDIR/demos/declarative/samegame.qml. The results of the individual steps are in the $QTDIR/examples/declarative/tutorials/samegame directory. + +Tutorial chapters: + +\list +\o \l {advtutorial1}{Advanced Tutorial 1 - Basic Game Screen and Block} +\o \l {advtutorial2}{Advanced Tutorial 2 - Dynamically create the Blocks} +\o \l {advtutorial3}{Advanced Tutorial 3 - Implement the Game Logic} +\o \l {advtutorial4}{Advanced Tutorial 4 - Finishing Touches} +\endlist + +*/ diff --git a/doc/src/declarative/advtutorial1.qdoc b/doc/src/declarative/advtutorial1.qdoc new file mode 100644 index 0000000..b940986 --- /dev/null +++ b/doc/src/declarative/advtutorial1.qdoc @@ -0,0 +1,116 @@ +/*! +\page advtutorial1.html +\example declarative/tutorials/samegame/samegame1 +\title Advanced Tutorial 1 - Creating the Game canvas and block +\target advtutorial1 + +The first step is to create the items in your application. In Same Game we have a main game screen and the blocks that populate it. + +\image declarative-adv-tutorial1.png + +Here is the QML code for the basic elements. The game window: + +\code +import Qt 4.6 + +Rectangle { + id: Screen + width: 490; height: 720 + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "pics/background.png" + fillMode: "PreserveAspectCrop" + } + } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: print("Implement me!"); + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: Who knows?"; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} +\endcode + +This gives you a basic game window, with room for the game canvas. A new game +button and room to display the score. The one thing you may not recognize here +is the SystemPalette item. This item provides access to the Qt system palette +and is used to make the button look more like a system button (for exact native +feel you would use a QPushButton). Since we want a fully QML button, and the Fx +primitives don't include a button, we had to write our own. Below is the code +which we wrote to do this: + +\code +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} +\endcode +Note that this Button component was written to be fairly generic, in case we +want to use a similarly styled button later. + +And here is a simple block: +\code +import Qt 4.6 + +Item { + id:block + + Image { id: img + source: "pics/redStone.png"; + anchors.fill: parent + } +} +\endcode + +Since it doesn't do anything yet it's very simple, just an image. As the +tutorial progresses and the block starts doing things the file will become +more than just an image. Note that we've set the image to be the size of the itm. This will be used later, when we dynamically create and size the block items the image will be scaled automatically to the correct size. + +You should be familiar with all that goes on in these files so far. This is a +very basic start and doesn't move at all - next we will populate the game canvas +with some blocks. + +[\l {advtutorial.html}{Advanced Tutorial}] [Next: \l {advtutorial2}{Advanced Tutorial 2}] +*/ + diff --git a/doc/src/declarative/advtutorial2.qdoc b/doc/src/declarative/advtutorial2.qdoc new file mode 100644 index 0000000..c17f9c4 --- /dev/null +++ b/doc/src/declarative/advtutorial2.qdoc @@ -0,0 +1,113 @@ +/*! +\page advtutorial2.html +\title Advanced Tutorial 2 - Populating the Game Canvas +\target advtutorial2 + +Now that we've written some basic elements, let's start writing the game. The +first thing to do is to generate all of the blocks. Now we need to dynamically +generate all of these blocks, because you have a new, random set of blocks +every time. As they are dynamically generated every time the new game button is +clicked, as opposed to on startup, we will be dynamically generating the blocks +in the ECMA script, as opposed to using a Repeater. + +This adds enough script to justify a new file, samegame.js, the intial version +of which is shown below + +\code +//Note that X/Y referred to here are in game coordinates +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; +var tileSize = 40; +var maxIndex = maxX*maxY; +var board = new Array(maxIndex); +var tileSrc = "Block.qml"; +var component; + +//Index function used instead of a 2D array +function index(xIdx,yIdx) { + return xIdx + (yIdx * maxX); +} + +function initBoard() +{ + //Calculate board size + maxX = Math.floor(background.width/tileSize); + maxY = Math.floor(background.height/tileSize); + maxIndex = maxY*maxX; + + //Initialize Board + board = new Array(maxIndex); + for(xIdx=0; xIdx= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + //If it's a valid tile, remove it and all connected (does nothing if it's not connected) + floodFill(xIdx,yIdx, -1); + if(fillFound <= 0) + return; + gameCanvas.score += (fillFound - 1) * (fillFound - 1); + shuffleDown(); + victoryCheck(); +} + +function victoryCheck() +{ + //awards bonuses for no tiles left + deservesBonus = true; + for(xIdx=maxX-1; xIdx>=0; xIdx--) + if(board[index(xIdx, maxY - 1)] != null) + deservesBonus = false; + if(deservesBonus) + gameCanvas.score += 500; + //Checks for game over + if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))) + dialog.show("Game Over. Your score is " + gameCanvas.score); +} +\endcode + +You'll notice them referring to the 'gameCanvas' item. This is an item that has been added to the QML for easy interfacing. It is placed next to the background image and replaces the background as the item to create the blocks in. Its code is shown below: +\code + Item { + id: gameCanvas + property int score: 0 + property int tileSize: 40 + + z: 20; anchors.centerIn: parent + width: parent.width - (parent.width % tileSize); + height: parent.height - (parent.height % tileSize); + + MouseRegion { + id: gameMR + anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); + } + } +\endcode + +This item is the exact size of the board, contains a score property, and a mouse region for input. The blocks are now created as its children, and its size is used as the noe determining board size. Since it needs to bind its size to a multiple of tileSize, tileSize needs to be moved into a QML property and out of the script file. It can still be accessed from the script. + +The mouse region simply calls handleClick(), which deals with the input events.Should those events cause the player to score, gameCanvas.score is updated. The score display text item has also been changed to bind its text property to gamecanvas.score. Note that if score was a global variable in the samegame.js file yo ucould not bind to it. You can only bind to QML properties. + +victoryCheck() mostly just updates score. But it also pops up a dialog saying 'Game Over' when the game is over. In this example we wanted a pure-QML, animated dialog, and since the Fx primitives set doesn't contain one, we wrote our own. Below is the code for the Dialog element, note how it's designed so as to be quite usable imperatively from within the script file: +\code +import Qt 4.6 + +Rectangle { + id: page + function forceClose() { + page.closed(); + page.opacity = 0; + } + function show(txt) { + MyText.text = txt; + page.opacity = 1; + } + signal closed(); + color: "white"; border.width: 1; width: MyText.width + 20; height: 60; + opacity: 0 + opacity: Behavior { + NumberAnimation { duration: 1000 } + } + Text { id: MyText; anchors.centerIn: parent; text: "Hello World!" } + MouseRegion { id: mr; anchors.fill: parent; onClicked: forceClose(); } +} +\endcode +And this is how it's used in the main QML file: +\code + Dialog { id: dialog; anchors.centerIn: parent; z: 21 } +\endcode +Combined with the line of code in victoryCheck, this causes a dialog to appear when the game is over, informing the user of that fact. + +We now have a working game! The blocks can be clicked, the player can score, and the game can end (and then you start a new one). Below is a screenshot of what has been accomplished so far: + +\image declarative-adv-tutorial3.png + +Here is the QML code as it is now for the main file: + +\code +import Qt 4.6 + +Rectangle { + id: Screen + width: 490; height: 720 + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + Script { source: "samegame.js" } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "pics/background.png" + fillMode: "PreserveAspectCrop" + } + + Item { + id: gameCanvas + property int score: 0 + property int tileSize: 40 + + z: 20; anchors.centerIn: parent + width: parent.width - (parent.width % tileSize); + height: parent.height - (parent.height % tileSize); + + MouseRegion { + id: gameMR + anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); + } + } + } + + Dialog { id: dialog; anchors.centerIn: parent; z: 21 } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: initBoard(); + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: " + gameCanvas.score; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} +\endcode + +And the code for the block: +\code +import Qt 4.6 + +Item { + id:block + property int type: 0 + + Image { id: img + source: { + if(type == 0){ + "pics/redStone.png"; + } else if(type == 1) { + "pics/blueStone.png"; + } else { + "pics/greenStone.png"; + } + } + anchors.fill: parent + } +} +\endcode + +The game works, but it's a little boring right now. Where's the smooth animated transitions? Where's the high scores? If you were a QML expert you could have written these in for the first iteration, but in this tutorial they've been saved until the next chapter - where your application becomes alive! + +[Previous: \l {advtutorial2}{Advanced Tutorial 2}] [\l {advtutorial.html}{Advanced Tutorial}] [Next: \l {advtutorial4}{Advanced Tutorial 4}] + +*/ + diff --git a/doc/src/declarative/advtutorial4.qdoc b/doc/src/declarative/advtutorial4.qdoc new file mode 100644 index 0000000..5ad1ec3 --- /dev/null +++ b/doc/src/declarative/advtutorial4.qdoc @@ -0,0 +1,120 @@ +/*! +\page advtutorial4.html +\title Advanced Tutorial 4 - Finishing Touches +\target advtutorial4 + +Now we're going to do two things to liven the game up. Animate the blocks and add a web-based high score system. + +If you compare the samegame3 directory with samegame4, you'll noticed that we've cleaned the directory structure up. We now have a lot of files, and so they've been split up into folders - the most notable one being a content folder which we've placed all the QML but the main file. + +\section2 Animated Blocks + +The most vital animations are that the blocks move fluidly around the board. QML has many tools for fluid behavior, and in this case we're going to use the Follow element. By having the script set targetX and targetY, instead of x and y directly, we can set the x and y of the block to a follow. SpringFollow is a property value source, which means that you can set a property to be one of these elements and it will automatically bind the property to the element's value. The SpringFollow's value follows another value over time, when the value it is tracking changes the SpringFollow's value will also change, but it will move smoothly there over time with a spring-like movement (based on the spring parameters specified). This is shown in the below snippet of code from Block.qml: +\code + property int targetX: 0 + property int targetY: 0 + + x: SpringFollow { source: targetX; spring: 2; damping: 0.2 } + y: SpringFollow { source: targetY; spring: 2; damping: 0.2 } +\endcode + +We also have to change the samegame.js code, so that wherever it was setting the x or y it now sets targetX and targetY (including when creating the block). This simple change is all you need to get spring moving blocks that no longer teleport around the board. If you try doing just this though, you'll notice that they now never jump from one point to another, even in the initialization! This gives an odd effect of having them all jump out of the corner (0,0) on start up. We'd rather that they fall down from the top in rows. To do this, we disable the x Follow (but not the y follow) and only enable it after we've set the x in the createBlock function. The above snippet now becomes: + +\code + property bool spawned: false + property int targetX: 0 + property int targetY: 0 + + x: SpringFollow { enabled: spawned; source: targetX; spring: 2; damping: 0.2 } + y: SpringFollow { source: targetY; spring: 2; damping: 0.2 } +\endcode + +The next-most vital animation is a smooth exit. For this animation, we'll use a Behavior element. A Behavior is also a property value source, and it is much like SpringFollow except that it doesn't model the behavior of a spring. You specify how a Behavior transitions using the standard animations. As we want the blocks to smoothly fade in and out we'll set a Behavior on the block image's opacity, like so: +\code + Image { id: img + source: { + if(type == 0){ + "pics/redStone.png"; + } else if(type == 1) { + "pics/blueStone.png"; + } else { + "pics/greenStone.png"; + } + } + opacity: 0 + opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } + anchors.fill: parent + } +\endcode + +Note that the 'opacity: 0' makes it start out transparent. We could set the opacity in the script file when we create the blocks, but instead we use states (as this is useful for the next animation we'll implement). The below snippet is set on the root element of Block.qml: +\code + property bool dying: false + states: [ + State{ name: "AliveState"; when: spawned == true && dying == false + PropertyChanges { target: img; opacity: 1 } + }, State{ name: "DeathState"; when: dying == true + PropertyChanges { target: img; opacity: 0 } + } + ] +\endcode + +Now it will automatically fade in, as we set spawned to true already when implementing the block movement animations. To fade out, we set 'dying' to true instead of setting opacity to 0 when a block is destroyed (in the floodFill function). + +The least vital animations are a cool-looking particle effect when they get destroyed. First we create a Particles Element in the block, like so: +\code + Particles { id: particles + width:1; height:1; anchors.centerIn: parent; opacity: 0 + lifeSpan: 700; lifeSpanDeviation: 600; count:0; streamIn: false + angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30 + source: { + if(type == 0){ + "pics/redStar.png"; + } else if (type == 1) { + "pics/blueStar.png"; + } else { + "pics/greenStar.png"; + } + } + } +\endcode +To fully understand this you'll want to look at the Particles element documentation, but it's important to note that count is set to zero. +We next extend the 'dying' state, which triggers the particles by setting the count to non-zero. The code for that state looks like this: +\code + State{ name: "DeathState"; when: dying == true + PropertyChanges { target: particles; count: 50 } + PropertyChanges { target: particles; opacity: 1 } + PropertyChanges { target: particles; emitting: false } // i.e. emit only once + PropertyChanges { target: img; opacity: 0 } + } +\endcode +And now the game should be beautifully animated and smooth, with a subtle (or not-so-subtle) animation added for all of the player's actions. + +\section2 Web-based High Scores + +Another extension we might want for the game is some way of storing and retriveing high scores. In this tutorial we'll show you how to integrate a web enabled high score storage into your QML application. The implementation we've done is very simple - the high score data is posted to a php script running on a server somewhere, and that server then stores it and displays it to visitors. You could request an XML or QML file from that same server, which contained and displayed the scores, but that's beyond the scope of this tutorial. + +For better high score data, we want the name and time of the player. The time is obtained in the script fairly simply, but we have to ask the player for their name. We thus re-use the dialog QML file to pop up a dialog asking for the player's name (and if they exit this dialog without entering it they have a way to opt out of posting their high score). When the dialog is closed, if the player entered their name we can send the data to the web service in the followign snippet out of the script file: +\code +function sendHighScore(name) { + var postman = new XMLHttpRequest() + var postData = "name="+name+"&score="+gameCanvas.score + +"&gridSize="+maxX+"x"+maxY +"&time="+Math.floor(timer/1000); + postman.open("POST", scoresURL, true); + postman.onreadystatechange = function() { + if (postman.readyState == postman.DONE) { + dialog.show("Your score has been uploaded."); + } + } + postman.send(postData); +} +\endcode + +This is the same XMLHttpRequest() as you'll find in browser javascript, and can be used in the same way to dynamically get XML or QML from the web service to display the high scores. We don't worry about the response here though, we just post the high score data to the web server. If it had returned a QML file (or a URL to a QML file) you could instantiate it in much the same way as you did the blocks. + +An alternate way to access and submit web-based data would be to use QML elements designed for this purpose - XmlListModel makes it very easy to fetch and display XML based data such as RSS in a QML application (see the Flickr demo for an example). + +By following this tutorial you've now ben shown how to write a fully functional application in QML, with the application logic written in a script file and with both many fluid animations and being web-enabled. Congratulations, you should now be skilled enough to write your own QML applications. + +[Previous: \l {advtutorial3}{Advanced Tutorial 3}] [\l {advtutorial.html}{Advanced Tutorial}] +*/ diff --git a/doc/src/declarative/qtdeclarative.qdoc b/doc/src/declarative/qtdeclarative.qdoc index 06cba15..f94b9f8 100644 --- a/doc/src/declarative/qtdeclarative.qdoc +++ b/doc/src/declarative/qtdeclarative.qdoc @@ -64,6 +64,7 @@ \list \o \l {qmlexamples}{Examples} \o \l {tutorial}{Tutorial: 'Hello World'} + \o \l {advtutorial.html}{Advanced Tutorial: 'Same Game'} \o \l {tutorials-declarative-contacts.html}{Tutorial: 'Introduction to QML'} \o \l {qmlforcpp}{QML For C++ Programmers} \endlist diff --git a/examples/declarative/tutorials/samegame/samegame1/Block.qml b/examples/declarative/tutorials/samegame/samegame1/Block.qml new file mode 100644 index 0000000..228ac4e --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/Block.qml @@ -0,0 +1,10 @@ +import Qt 4.6 + +Item { + id:block + + Image { id: img + source: "pics/redStone.png"; + anchors.fill: parent + } +} diff --git a/examples/declarative/tutorials/samegame/samegame1/Button.qml b/examples/declarative/tutorials/samegame/samegame1/Button.qml new file mode 100644 index 0000000..2354218 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/Button.qml @@ -0,0 +1,25 @@ +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} diff --git a/examples/declarative/tutorials/samegame/samegame1/pics/background.png b/examples/declarative/tutorials/samegame/samegame1/pics/background.png new file mode 100644 index 0000000..25e885f Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame1/pics/background.png differ diff --git a/examples/declarative/tutorials/samegame/samegame1/pics/redStone.png b/examples/declarative/tutorials/samegame/samegame1/pics/redStone.png new file mode 100644 index 0000000..b099f60 Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame1/pics/redStone.png differ diff --git a/examples/declarative/tutorials/samegame/samegame1/samegame.qml b/examples/declarative/tutorials/samegame/samegame1/samegame.qml new file mode 100644 index 0000000..d18718d --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame1/samegame.qml @@ -0,0 +1,38 @@ +import Qt 4.6 + +Rectangle { + id: Screen + width: 490; height: 720 + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "pics/background.png" + fillMode: "PreserveAspectCrop" + } + } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: print("Implement me!"); + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: Who knows?"; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} diff --git a/examples/declarative/tutorials/samegame/samegame2/Block.qml b/examples/declarative/tutorials/samegame/samegame2/Block.qml new file mode 100644 index 0000000..228ac4e --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/Block.qml @@ -0,0 +1,10 @@ +import Qt 4.6 + +Item { + id:block + + Image { id: img + source: "pics/redStone.png"; + anchors.fill: parent + } +} diff --git a/examples/declarative/tutorials/samegame/samegame2/Button.qml b/examples/declarative/tutorials/samegame/samegame2/Button.qml new file mode 100644 index 0000000..2354218 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/Button.qml @@ -0,0 +1,25 @@ +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} diff --git a/examples/declarative/tutorials/samegame/samegame2/pics/background.png b/examples/declarative/tutorials/samegame/samegame2/pics/background.png new file mode 100644 index 0000000..25e885f Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame2/pics/background.png differ diff --git a/examples/declarative/tutorials/samegame/samegame2/pics/redStone.png b/examples/declarative/tutorials/samegame/samegame2/pics/redStone.png new file mode 100644 index 0000000..b099f60 Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame2/pics/redStone.png differ diff --git a/examples/declarative/tutorials/samegame/samegame2/samegame.js b/examples/declarative/tutorials/samegame/samegame2/samegame.js new file mode 100644 index 0000000..064d87e --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame2/samegame.js @@ -0,0 +1,59 @@ +//Note that X/Y referred to here are in game coordinates +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; +var tileSize = 40; +var maxIndex = maxX*maxY; +var board = new Array(maxIndex); +var tileSrc = "Block.qml"; +var component; + +//Index function used instead of a 2D array +function index(xIdx,yIdx) { + return xIdx + (yIdx * maxX); +} + +function initBoard() +{ + //Calculate board size + maxX = Math.floor(background.width/tileSize); + maxY = Math.floor(background.height/tileSize); + maxIndex = maxY*maxX; + + //Initialize Board + board = new Array(maxIndex); + for(xIdx=0; xIdx= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + //If it's a valid tile, remove it and all connected (does nothing if it's not connected) + floodFill(xIdx,yIdx, -1); + if(fillFound <= 0) + return; + gameCanvas.score += (fillFound - 1) * (fillFound - 1); + shuffleDown(); + victoryCheck(); +} + +function floodFill(xIdx,yIdx,type) +{ + if(board[index(xIdx, yIdx)] == null) + return; + var first = false; + if(type == -1){ + first = true; + type = board[index(xIdx,yIdx)].type; + + //Flood fill initialization + fillFound = 0; + floodBoard = new Array(maxIndex); + } + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(floodBoard[index(xIdx, yIdx)] == 1 || (!first && type != board[index(xIdx,yIdx)].type)) + return; + floodBoard[index(xIdx, yIdx)] = 1; + floodFill(xIdx+1,yIdx,type); + floodFill(xIdx-1,yIdx,type); + floodFill(xIdx,yIdx+1,type); + floodFill(xIdx,yIdx-1,type); + if(first==true && fillFound == 0) + return;//Can't remove single tiles + board[index(xIdx,yIdx)].opacity = 0; + board[index(xIdx,yIdx)] = null; + fillFound += 1; +} + +function shuffleDown() +{ + //Fall down + for(xIdx=0; xIdx=0; yIdx--){ + if(board[index(xIdx,yIdx)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + obj = board[index(xIdx,yIdx)]; + obj.y += fallDist * gameCanvas.tileSize; + board[index(xIdx,yIdx+fallDist)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } + //Fall to the left + fallDist = 0; + for(xIdx=0; xIdx 0){ + for(yIdx=0; yIdx=0; xIdx--) + if(board[index(xIdx, maxY - 1)] != null) + deservesBonus = false; + if(deservesBonus) + gameCanvas.score += 500; + //Checks for game over + if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))) + dialog.show("Game Over. Your score is " + gameCanvas.score); +} + +//only floods up and right, to see if it can find adjacent same-typed tiles +function floodMoveCheck(xIdx, yIdx, type) +{ + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return false; + if(board[index(xIdx, yIdx)] == null) + return false; + myType = board[index(xIdx, yIdx)].type; + if(type == myType) + return true; + return floodMoveCheck(xIdx + 1, yIdx, myType) || + floodMoveCheck(xIdx, yIdx - 1, board[index(xIdx,yIdx)].type); +} diff --git a/examples/declarative/tutorials/samegame/samegame3/samegame.qml b/examples/declarative/tutorials/samegame/samegame3/samegame.qml new file mode 100644 index 0000000..ea43ab2 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame3/samegame.qml @@ -0,0 +1,56 @@ +import Qt 4.6 + +Rectangle { + id: Screen + width: 490; height: 720 + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + Script { source: "samegame.js" } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "pics/background.png" + fillMode: "PreserveAspectCrop" + } + + Item { + id: gameCanvas + property int score: 0 + property int tileSize: 40 + + z: 20; anchors.centerIn: parent + width: parent.width - (parent.width % tileSize); + height: parent.height - (parent.height % tileSize); + + MouseRegion { + id: gameMR + anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); + } + } + } + + Dialog { id: dialog; anchors.centerIn: parent; z: 21 } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: initBoard(); + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: " + gameCanvas.score; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} diff --git a/examples/declarative/tutorials/samegame/samegame4/README b/examples/declarative/tutorials/samegame/samegame4/README new file mode 100644 index 0000000..244b205 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/README @@ -0,0 +1,10 @@ +This demo uses pictures from the KDE project (www.kde.org), +specifically the images from the KSame game. These images are + +background.png +blueStone.png +redStone.png +greenStone.png +yellowStone.png + +and are presumably under the same GPL2 license as the rest of kdegames diff --git a/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml b/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml new file mode 100644 index 0000000..a495cd0 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml @@ -0,0 +1,54 @@ +import Qt 4.6 + +Item { id:block + property bool dying: false + property bool spawned: false + property int type: 0 + property int targetX: 0 + property int targetY: 0 + + x: SpringFollow { enabled: spawned; source: targetX; spring: 2; damping: 0.2 } + y: SpringFollow { source: targetY; spring: 2; damping: 0.2 } + + Image { id: img + source: { + if(type == 0){ + "pics/redStone.png"; + } else if(type == 1) { + "pics/blueStone.png"; + } else { + "pics/greenStone.png"; + } + } + opacity: 0 + opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } + anchors.fill: parent + } + + Particles { id: particles + width:1; height:1; anchors.centerIn: parent; opacity: 0 + lifeSpan: 700; lifeSpanDeviation: 600; count:0; streamIn: false + angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30 + source: { + if(type == 0){ + "pics/redStar.png"; + } else if (type == 1) { + "pics/blueStar.png"; + } else { + "pics/greenStar.png"; + } + } + } + + states: [ + State{ name: "AliveState"; when: spawned == true && dying == false + PropertyChanges { target: img; opacity: 1 } + }, + State{ name: "DeathState"; when: dying == true + PropertyChanges { target: particles; count: 50 } + PropertyChanges { target: particles; opacity: 1 } + PropertyChanges { target: particles; emitting: false } // i.e. emit only once + PropertyChanges { target: img; opacity: 0 } + } + ] +} diff --git a/examples/declarative/tutorials/samegame/samegame4/content/Button.qml b/examples/declarative/tutorials/samegame/samegame4/content/Button.qml new file mode 100644 index 0000000..2354218 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/Button.qml @@ -0,0 +1,25 @@ +import Qt 4.6 + +Rectangle { + id: Container + + signal clicked + property string text: "Button" + + color: activePalette.button; smooth: true + width: txtItem.width + 20; height: txtItem.height + 6 + border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; + + gradient: Gradient { + GradientStop { + id: topGrad; position: 0.0 + color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } + GradientStop { position: 1.0; color: activePalette.button } + } + + MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } + + Text { + id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText + } +} diff --git a/examples/declarative/tutorials/samegame/samegame4/content/Dialog.qml b/examples/declarative/tutorials/samegame/samegame4/content/Dialog.qml new file mode 100644 index 0000000..401d211 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/Dialog.qml @@ -0,0 +1,21 @@ +import Qt 4.6 + +Rectangle { + id: page + function forceClose() { + page.closed(); + page.opacity = 0; + } + function show(txt) { + MyText.text = txt; + page.opacity = 1; + } + signal closed(); + color: "white"; border.width: 1; width: MyText.width + 20; height: 60; + opacity: 0 + opacity: Behavior { + NumberAnimation { duration: 1000 } + } + Text { id: MyText; anchors.centerIn: parent; text: "Hello World!" } + MouseRegion { id: mr; anchors.fill: parent; onClicked: forceClose(); } +} diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/background.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/background.png new file mode 100644 index 0000000..25e885f Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/background.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStar.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStar.png new file mode 100644 index 0000000..ff9588f Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStar.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStone.png new file mode 100644 index 0000000..bf342e0 Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/blueStone.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStar.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStar.png new file mode 100644 index 0000000..cd06854 Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStar.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStone.png new file mode 100644 index 0000000..5ac14a5 Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/greenStone.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/redStar.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStar.png new file mode 100644 index 0000000..0a4dffe Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStar.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/redStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStone.png new file mode 100644 index 0000000..b099f60 Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/redStone.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/star.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/star.png new file mode 100644 index 0000000..defbde5 Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/star.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/pics/yellowStone.png b/examples/declarative/tutorials/samegame/samegame4/content/pics/yellowStone.png new file mode 100644 index 0000000..c56124a Binary files /dev/null and b/examples/declarative/tutorials/samegame/samegame4/content/pics/yellowStone.png differ diff --git a/examples/declarative/tutorials/samegame/samegame4/content/samegame.js b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js new file mode 100755 index 0000000..cf55b59 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js @@ -0,0 +1,217 @@ +/* This script file handles the game logic */ +//Note that X/Y referred to here are in game coordinates +var maxX = 10;//Nums are for tileSize 40 +var maxY = 15; +var tileSize = 40; +var maxIndex = maxX*maxY; +var board = new Array(maxIndex); +var tileSrc = "content/BoomBlock.qml"; +var scoresURL = "http://qtfx-nokia.trolltech.com.au/samegame/scores.php"; +var timer; +var component; + +//Index function used instead of a 2D array +function index(xIdx,yIdx) { + return xIdx + (yIdx * maxX); +} + +function timeStr(msecs) { + var secs = Math.floor(msecs/1000); + var m = Math.floor(secs/60); + var ret = "" + m + "m " + (secs%60) + "s"; + return ret; +} + +function initBoard() +{ + for(i = 0; i= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(board[index(xIdx, yIdx)] == null) + return; + //If it's a valid tile, remove it and all connected (does nothing if it's not connected) + floodFill(xIdx,yIdx, -1); + if(fillFound <= 0) + return; + gameCanvas.score += (fillFound - 1) * (fillFound - 1); + shuffleDown(); + victoryCheck(); +} + +function floodFill(xIdx,yIdx,type) +{ + if(board[index(xIdx, yIdx)] == null) + return; + var first = false; + if(type == -1){ + first = true; + type = board[index(xIdx,yIdx)].type; + + //Flood fill initialization + fillFound = 0; + floodBoard = new Array(maxIndex); + } + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return; + if(floodBoard[index(xIdx, yIdx)] == 1 || (!first && type != board[index(xIdx,yIdx)].type)) + return; + floodBoard[index(xIdx, yIdx)] = 1; + floodFill(xIdx+1,yIdx,type); + floodFill(xIdx-1,yIdx,type); + floodFill(xIdx,yIdx+1,type); + floodFill(xIdx,yIdx-1,type); + if(first==true && fillFound == 0) + return;//Can't remove single tiles + board[index(xIdx,yIdx)].dying = true; + board[index(xIdx,yIdx)] = null; + fillFound += 1; +} + +function shuffleDown() +{ + //Fall down + for(xIdx=0; xIdx=0; yIdx--){ + if(board[index(xIdx,yIdx)] == null){ + fallDist += 1; + }else{ + if(fallDist > 0){ + obj = board[index(xIdx,yIdx)]; + obj.targetY += fallDist * tileSize; + board[index(xIdx,yIdx+fallDist)] = obj; + board[index(xIdx,yIdx)] = null; + } + } + } + } + //Fall to the left + fallDist = 0; + for(xIdx=0; xIdx 0){ + for(yIdx=0; yIdx=0; xIdx--) + if(board[index(xIdx, maxY - 1)] != null) + deservesBonus = false; + if(deservesBonus) + gameCanvas.score += 500; + //Checks for game over + if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))){ + timer = new Date() - timer; + if(scoresURL != "") + scoreName.show("You've won! Please enter your name: "); + else + dialog.show("Game Over. Your score is " + gameCanvas.score); + } +} + +//only floods up and right, to see if it can find adjacent same-typed tiles +function floodMoveCheck(xIdx, yIdx, type) +{ + if(xIdx >= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) + return false; + if(board[index(xIdx, yIdx)] == null) + return false; + myType = board[index(xIdx, yIdx)].type; + if(type == myType) + return true; + return floodMoveCheck(xIdx + 1, yIdx, myType) || + floodMoveCheck(xIdx, yIdx - 1, board[index(xIdx,yIdx)].type); +} + +function createBlock(xIdx,yIdx){ + if(component==null) + component = createComponent(tileSrc); + + // Note that we don't wait for the component to become ready. This will + // only work if the block QML is a local file. Otherwise the component will + // not be ready immediately. There is a statusChanged signal on the + // component you could use if you want to wait to load remote files. + if(component.isReady){ + dynamicObject = component.createObject(); + if(dynamicObject == null){ + print("error creating block"); + print(component.errorsString()); + return false; + } + dynamicObject.type = Math.floor(Math.random() * 3); + dynamicObject.parent = gameCanvas; + dynamicObject.x = xIdx*tileSize; + dynamicObject.targetX = xIdx*tileSize; + dynamicObject.targetY = yIdx*tileSize; + dynamicObject.width = tileSize; + dynamicObject.height = tileSize; + dynamicObject.spawned = true; + board[index(xIdx,yIdx)] = dynamicObject; + }else{//isError or isLoading + print("error loading block component"); + print(component.errorsString()); + return false; + } + return true; +} + +function sendHighScore(name) { + var postman = new XMLHttpRequest() + var postData = "name="+name+"&score="+gameCanvas.score + +"&gridSize="+maxX+"x"+maxY +"&time="+Math.floor(timer/1000); + postman.open("POST", scoresURL, true); + postman.onreadystatechange = function() { + if (postman.readyState == postman.DONE) { + dialog.show("Your score has been uploaded."); + } + } + postman.send(postData); +} diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/README b/examples/declarative/tutorials/samegame/samegame4/highscores/README new file mode 100644 index 0000000..eaa00fa --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/README @@ -0,0 +1 @@ +The SameGame example can interface with a simple PHP script to store XML high score data on a remote server. We do not have a publically accessible server available for this use, but if you have access to a PHP capable webserver you can copy the files (score_data.xml, score.php, score_style.xsl) to it and alter the highscore_server variable at the top of the samegame.js file to point to it. diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/score_data.xml b/examples/declarative/tutorials/samegame/samegame4/highscores/score_data.xml new file mode 100755 index 0000000..c3fd90d --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/score_data.xml @@ -0,0 +1,2 @@ +1000000Alan the Tester0x00 +6213Alan12x1751 diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/score_style.xsl b/examples/declarative/tutorials/samegame/samegame4/highscores/score_style.xsl new file mode 100755 index 0000000..670354c --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/score_style.xsl @@ -0,0 +1,28 @@ + + + + + SameGame High Scores + +

SameGame High Scores

+
+ + + + + + + + + + + + + + + +
NameScoreGrid SizeTime, s
+ + + + diff --git a/examples/declarative/tutorials/samegame/samegame4/highscores/scores.php b/examples/declarative/tutorials/samegame/samegame4/highscores/scores.php new file mode 100755 index 0000000..3cceb2d --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/highscores/scores.php @@ -0,0 +1,34 @@ +"; + echo "SameGame High Scores"; + if($score > 0){#Sending in a new high score + $name = $_POST["name"]; + $grid = $_POST["gridSize"]; + $time = $_POST["time"]; + if($name == "") + $name = "Anonymous"; + //if($grid != "10x10"){ + //Need a standard, so as to reject others? + //} + $file = fopen("score_data.xml", "a"); #It's XML. Happy? + $ret = fwrite($file, "". $score . "" + . $name . "" . $grid . "" + . $time . "\n"); + echo "Your score has been recorded. Thanks for playing!"; + if($ret == False) + echo "
There was an error though, so don't expect to see that score again."; + }else{#Read high score list + #Now uses XSLT to display. So just print the file. With XML cruft added. + #Note that firefox at least won't apply the XSLT on a php file. So redirecting + $file = fopen("scores.xml", "w"); + $ret = fwrite($file, '' . "\n" + . '' . "\n" + . "\n" . file_get_contents("score_data.xml") . "\n"); + if($ret == False) + echo "There was an internal error. Sorry."; + else + echo ''; + } + echo ""; +?> diff --git a/examples/declarative/tutorials/samegame/samegame4/samegame.qml b/examples/declarative/tutorials/samegame/samegame4/samegame.qml new file mode 100644 index 0000000..ede4362 --- /dev/null +++ b/examples/declarative/tutorials/samegame/samegame4/samegame.qml @@ -0,0 +1,71 @@ +import Qt 4.6 +import "content" + +Rectangle { + id: Screen + width: 490; height: 720 + + Script { source: "content/samegame.js" } + + SystemPalette { id: activePalette; colorGroup: Qt.Active } + + Item { + width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top + + Image { + id: background + anchors.fill: parent; source: "content/pics/background.png" + fillMode: "PreserveAspectCrop" + } + + Item { + id: gameCanvas + property int score: 0 + + z: 20; anchors.centerIn: parent + width: parent.width - (parent.width % tileSize); + height: parent.height - (parent.height % tileSize); + + MouseRegion { + id: gameMR + anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); + } + } + } + + Dialog { id: dialog; anchors.centerIn: parent; z: 21 } + Dialog { + id: scoreName; anchors.centerIn: parent; z: 22; + TextInput { + id: Editor + onAccepted: { + if(scoreName.opacity==1&&Editor.text!="") + sendHighScore(Editor.text); + scoreName.forceClose(); + } + anchors.verticalCenter: parent.verticalCenter + width: 72; focus: true + anchors.right: scoreName.right + } + } + + Rectangle { + id: ToolBar + color: activePalette.window + height: 32; width: parent.width + anchors.bottom: Screen.bottom + + Button { + id: btnA; text: "New Game"; onClicked: {initBoard();} + anchors.left: parent.left; anchors.leftMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + + Text { + id: Score + text: "Score: " + gameCanvas.score; font.bold: true + anchors.right: parent.right; anchors.rightMargin: 3 + anchors.verticalCenter: parent.verticalCenter + } + } +} -- cgit v0.12 From e1452cfc79a1fed77e646427092e181b7eb2ca2f Mon Sep 17 00:00:00 2001 From: Warwick Allison Date: Wed, 7 Oct 2009 11:18:22 +1000 Subject: Fix portability of visual tests: fix filenames to be relative to base (URL). Still not font-portable. --- .../bindinganimation/data/bindinganimation.qml | 4 ++-- .../visual/colorAnimation/data/colorAnimation.qml | 6 +++--- tests/auto/declarative/visual/easing/data/easing.qml | 6 +++--- .../declarative/visual/flickable/data/flickable.qml | 6 +++--- .../auto/declarative/visual/focusscope/data/test.qml | 12 ++++++------ .../declarative/visual/focusscope/data/test2.qml | 4 ++-- .../declarative/visual/focusscope/data/test3.qml | 20 ++++++++++---------- .../visual/pauseAnimation/data/pauseAnimation.qml | 12 ++++++------ .../declarative/visual/qfxtext/elide/data/elide.qml | 2 +- .../auto/declarative/visual/repeater/data/basic1.qml | 2 +- .../auto/declarative/visual/repeater/data/basic2.qml | 2 +- .../auto/declarative/visual/repeater/data/basic3.qml | 2 +- .../auto/declarative/visual/repeater/data/basic4.qml | 2 +- tests/auto/declarative/visual/tst_visual.cpp | 2 ++ tools/qmlviewer/qfxtester.cpp | 4 ++-- tools/qmlviewer/qfxtester.h | 8 ++++---- 16 files changed, 48 insertions(+), 46 deletions(-) diff --git a/tests/auto/declarative/visual/bindinganimation/data/bindinganimation.qml b/tests/auto/declarative/visual/bindinganimation/data/bindinganimation.qml index 1d2f6da..2501797 100644 --- a/tests/auto/declarative/visual/bindinganimation/data/bindinganimation.qml +++ b/tests/auto/declarative/visual/bindinganimation/data/bindinganimation.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/bindinganimation/data/bindinganimation.0.png" + image: "bindinganimation.0.png" } Frame { msec: 976 @@ -498,7 +498,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/bindinganimation/data/bindinganimation.1.png" + image: "bindinganimation.1.png" } Frame { msec: 1936 diff --git a/tests/auto/declarative/visual/colorAnimation/data/colorAnimation.qml b/tests/auto/declarative/visual/colorAnimation/data/colorAnimation.qml index 8f7f068..6654021 100644 --- a/tests/auto/declarative/visual/colorAnimation/data/colorAnimation.qml +++ b/tests/auto/declarative/visual/colorAnimation/data/colorAnimation.qml @@ -258,7 +258,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/colorAnimation/data/colorAnimation.0.png" + image: "colorAnimation.0.png" } Frame { msec: 976 @@ -498,7 +498,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/colorAnimation/data/colorAnimation.1.png" + image: "colorAnimation.1.png" } Frame { msec: 1936 @@ -738,7 +738,7 @@ VisualTest { } Frame { msec: 2880 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/colorAnimation/data/colorAnimation.2.png" + image: "colorAnimation.2.png" } Frame { msec: 2896 diff --git a/tests/auto/declarative/visual/easing/data/easing.qml b/tests/auto/declarative/visual/easing/data/easing.qml index d991596..c41d676 100644 --- a/tests/auto/declarative/visual/easing/data/easing.qml +++ b/tests/auto/declarative/visual/easing/data/easing.qml @@ -258,7 +258,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/easing/data/easing.0.png" + image: "easing.0.png" } Frame { msec: 976 @@ -514,7 +514,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/easing/data/easing.1.png" + image: "easing.1.png" } Frame { msec: 1936 @@ -770,7 +770,7 @@ VisualTest { } Frame { msec: 2880 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/easing/data/easing.2.png" + image: "easing.2.png" } Frame { msec: 2896 diff --git a/tests/auto/declarative/visual/flickable/data/flickable.qml b/tests/auto/declarative/visual/flickable/data/flickable.qml index 45bb989..730c128 100644 --- a/tests/auto/declarative/visual/flickable/data/flickable.qml +++ b/tests/auto/declarative/visual/flickable/data/flickable.qml @@ -298,7 +298,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/flickable/data/flickable.0.png" + image: "flickable.0.png" } Frame { msec: 976 @@ -538,7 +538,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/flickable/data/flickable.1.png" + image: "flickable.1.png" } Frame { msec: 1936 @@ -786,6 +786,6 @@ VisualTest { } Frame { msec: 2880 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/flickable/data/flickable.2.png" + image: "flickable.2.png" } } diff --git a/tests/auto/declarative/visual/focusscope/data/test.qml b/tests/auto/declarative/visual/focusscope/data/test.qml index 95e23fc..d86c034 100644 --- a/tests/auto/declarative/visual/focusscope/data/test.qml +++ b/tests/auto/declarative/visual/focusscope/data/test.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test.0.png" + image: "test.0.png" } Frame { msec: 976 @@ -506,7 +506,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test.1.png" + image: "test.1.png" } Frame { msec: 1936 @@ -770,7 +770,7 @@ VisualTest { } Frame { msec: 2880 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test.2.png" + image: "test.2.png" } Frame { msec: 2896 @@ -1042,7 +1042,7 @@ VisualTest { } Frame { msec: 3840 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test.3.png" + image: "test.3.png" } Frame { msec: 3856 @@ -1306,7 +1306,7 @@ VisualTest { } Frame { msec: 4800 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test.4.png" + image: "test.4.png" } Frame { msec: 4816 @@ -1554,7 +1554,7 @@ VisualTest { } Frame { msec: 5760 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test.5.png" + image: "test.5.png" } Frame { msec: 5776 diff --git a/tests/auto/declarative/visual/focusscope/data/test2.qml b/tests/auto/declarative/visual/focusscope/data/test2.qml index 4ad4b89..fedc96a 100644 --- a/tests/auto/declarative/visual/focusscope/data/test2.qml +++ b/tests/auto/declarative/visual/focusscope/data/test2.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test2.0.png" + image: "test2.0.png" } Frame { msec: 976 @@ -482,7 +482,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test2.1.png" + image: "test2.1.png" } Frame { msec: 1936 diff --git a/tests/auto/declarative/visual/focusscope/data/test3.qml b/tests/auto/declarative/visual/focusscope/data/test3.qml index 86025a6..8ce7944 100644 --- a/tests/auto/declarative/visual/focusscope/data/test3.qml +++ b/tests/auto/declarative/visual/focusscope/data/test3.qml @@ -258,7 +258,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.0.png" + image: "test3.0.png" } Frame { msec: 976 @@ -530,7 +530,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.1.png" + image: "test3.1.png" } Frame { msec: 1936 @@ -802,7 +802,7 @@ VisualTest { } Frame { msec: 2880 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.2.png" + image: "test3.2.png" } Frame { msec: 2896 @@ -1074,7 +1074,7 @@ VisualTest { } Frame { msec: 3840 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.3.png" + image: "test3.3.png" } Frame { msec: 3856 @@ -1330,7 +1330,7 @@ VisualTest { } Frame { msec: 4800 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.4.png" + image: "test3.4.png" } Frame { msec: 4816 @@ -1594,7 +1594,7 @@ VisualTest { } Frame { msec: 5760 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.5.png" + image: "test3.5.png" } Frame { msec: 5776 @@ -1858,7 +1858,7 @@ VisualTest { } Frame { msec: 6720 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.6.png" + image: "test3.6.png" } Frame { msec: 6736 @@ -2130,7 +2130,7 @@ VisualTest { } Frame { msec: 7680 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.7.png" + image: "test3.7.png" } Frame { msec: 7696 @@ -2402,7 +2402,7 @@ VisualTest { } Frame { msec: 8640 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.8.png" + image: "test3.8.png" } Frame { msec: 8656 @@ -2658,7 +2658,7 @@ VisualTest { } Frame { msec: 9600 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/focusscope/data/test3.9.png" + image: "test3.9.png" } Frame { msec: 9616 diff --git a/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.qml b/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.qml index 5d42d03..73c6542 100644 --- a/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.qml +++ b/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.0.png" + image: "pauseAnimation.0.png" } Frame { msec: 976 @@ -482,7 +482,7 @@ VisualTest { } Frame { msec: 1920 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.1.png" + image: "pauseAnimation.1.png" } Frame { msec: 1936 @@ -722,7 +722,7 @@ VisualTest { } Frame { msec: 2880 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.2.png" + image: "pauseAnimation.2.png" } Frame { msec: 2896 @@ -962,7 +962,7 @@ VisualTest { } Frame { msec: 3840 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.3.png" + image: "pauseAnimation.3.png" } Frame { msec: 3856 @@ -1202,7 +1202,7 @@ VisualTest { } Frame { msec: 4800 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.4.png" + image: "pauseAnimation.4.png" } Frame { msec: 4816 @@ -1442,7 +1442,7 @@ VisualTest { } Frame { msec: 5760 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/pauseAnimation/data/pauseAnimation.5.png" + image: "pauseAnimation.5.png" } Frame { msec: 5776 diff --git a/tests/auto/declarative/visual/qfxtext/elide/data/elide.qml b/tests/auto/declarative/visual/qfxtext/elide/data/elide.qml index e62c1b7..59f17f7 100644 --- a/tests/auto/declarative/visual/qfxtext/elide/data/elide.qml +++ b/tests/auto/declarative/visual/qfxtext/elide/data/elide.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/qfxtext/elide/data/elide.0.png" + image: "elide.0.png" } Frame { msec: 976 diff --git a/tests/auto/declarative/visual/repeater/data/basic1.qml b/tests/auto/declarative/visual/repeater/data/basic1.qml index ad7e911..9535a2c 100644 --- a/tests/auto/declarative/visual/repeater/data/basic1.qml +++ b/tests/auto/declarative/visual/repeater/data/basic1.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/repeater/data/basic1.0.png" + image: "basic1.0.png" } Frame { msec: 976 diff --git a/tests/auto/declarative/visual/repeater/data/basic2.qml b/tests/auto/declarative/visual/repeater/data/basic2.qml index 082f349..81bc1f7 100644 --- a/tests/auto/declarative/visual/repeater/data/basic2.qml +++ b/tests/auto/declarative/visual/repeater/data/basic2.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/repeater/data/basic2.0.png" + image: "basic2.0.png" } Frame { msec: 976 diff --git a/tests/auto/declarative/visual/repeater/data/basic3.qml b/tests/auto/declarative/visual/repeater/data/basic3.qml index e76bf6f..417eaab 100644 --- a/tests/auto/declarative/visual/repeater/data/basic3.qml +++ b/tests/auto/declarative/visual/repeater/data/basic3.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/repeater/data/basic3.0.png" + image: "basic3.0.png" } Frame { msec: 976 diff --git a/tests/auto/declarative/visual/repeater/data/basic4.qml b/tests/auto/declarative/visual/repeater/data/basic4.qml index cdff83f..264d825 100644 --- a/tests/auto/declarative/visual/repeater/data/basic4.qml +++ b/tests/auto/declarative/visual/repeater/data/basic4.qml @@ -242,7 +242,7 @@ VisualTest { } Frame { msec: 960 - image: "/Users/akennedy/Qt/kinetic/tests/auto/declarative/visual/repeater/data/basic4.0.png" + image: "basic4.0.png" } Frame { msec: 976 diff --git a/tests/auto/declarative/visual/tst_visual.cpp b/tests/auto/declarative/visual/tst_visual.cpp index 458b96e..d95fa5b 100644 --- a/tests/auto/declarative/visual/tst_visual.cpp +++ b/tests/auto/declarative/visual/tst_visual.cpp @@ -78,6 +78,8 @@ void tst_visual::visual() QProcess p; p.start(qmlviewer, arguments); QVERIFY(p.waitForFinished()); + if (p.exitCode() != 0) + qDebug() << p.readAllStandardError(); QCOMPARE(p.exitStatus(), QProcess::NormalExit); QCOMPARE(p.exitCode(), 0); } diff --git a/tools/qmlviewer/qfxtester.cpp b/tools/qmlviewer/qfxtester.cpp index 7903fa9..a6a46eb 100644 --- a/tools/qmlviewer/qfxtester.cpp +++ b/tools/qmlviewer/qfxtester.cpp @@ -285,9 +285,9 @@ void QFxTester::updateCurrentTime(int msec) } if (options & QmlViewer::TestImages && !frame->image().isEmpty()) { - QImage goodImage(frame->image()); + QImage goodImage(frame->image().toLocalFile()); if (goodImage != img) { - QString reject(frame->image() + ".reject.png"); + QString reject(frame->image().toLocalFile() + ".reject.png"); qWarning() << "QFxTester: Image mismatch. Reject saved to:" << reject; img.save(reject); diff --git a/tools/qmlviewer/qfxtester.h b/tools/qmlviewer/qfxtester.h index bb027f6..52987db 100644 --- a/tools/qmlviewer/qfxtester.h +++ b/tools/qmlviewer/qfxtester.h @@ -44,7 +44,7 @@ class QFxVisualTestFrame : public QObject Q_OBJECT Q_PROPERTY(int msec READ msec WRITE setMsec) Q_PROPERTY(QString hash READ hash WRITE setHash) - Q_PROPERTY(QString image READ image WRITE setImage) + Q_PROPERTY(QUrl image READ image WRITE setImage) public: QFxVisualTestFrame() : m_msec(-1) {} @@ -54,13 +54,13 @@ public: QString hash() const { return m_hash; } void setHash(const QString &hash) { m_hash = hash; } - QString image() const { return m_image; } - void setImage(const QString &image) { m_image = image; } + QUrl image() const { return m_image; } + void setImage(const QUrl &image) { m_image = image; } private: int m_msec; QString m_hash; - QString m_image; + QUrl m_image; }; QML_DECLARE_TYPE(QFxVisualTestFrame) -- cgit v0.12 From a996e73fa08f97ddbe5b860445d2ec7bd5cd69d0 Mon Sep 17 00:00:00 2001 From: Bea Lam Date: Wed, 7 Oct 2009 11:31:36 +1000 Subject: Remove QFxFlowView and flowview example (will be moved to research/declarative-ui-examples). Functionality should eventually be added to grid view. --- examples/declarative/flowview/FlickrView.qml | 46 ---- examples/declarative/flowview/RoundedRect.qml | 4 - examples/declarative/flowview/flowview.qml | 147 ---------- src/declarative/extra/extra.pri | 2 - src/declarative/extra/qfxflowview.cpp | 379 -------------------------- src/declarative/extra/qfxflowview.h | 108 -------- 6 files changed, 686 deletions(-) delete mode 100644 examples/declarative/flowview/FlickrView.qml delete mode 100644 examples/declarative/flowview/RoundedRect.qml delete mode 100644 examples/declarative/flowview/flowview.qml delete mode 100644 src/declarative/extra/qfxflowview.cpp delete mode 100644 src/declarative/extra/qfxflowview.h diff --git a/examples/declarative/flowview/FlickrView.qml b/examples/declarative/flowview/FlickrView.qml deleted file mode 100644 index b73ae1a..0000000 --- a/examples/declarative/flowview/FlickrView.qml +++ /dev/null @@ -1,46 +0,0 @@ -import Qt 4.6 - -Rectangle { - radius: 5; - border.width: 1; - width:400; - height: 120; - color: background; - - XmlListModel { - id: feedModel - source: "http://api.flickr.com/services/feeds/photos_public.gne?format=rss2" - query: "/rss/channel/item" - namespaceDeclarations: "declare namespace media=\"http://search.yahoo.com/mrss/\";" - - XmlRole { name: "title"; query: "title/string()" } - XmlRole { name: "imagePath"; query: "media:thumbnail/@url/string()" } - XmlRole { name: "url"; query: "media:content/@url/string()" } - XmlRole { name: "description"; query: "description/string()" } - XmlRole { name: "tags"; query: "media:category/string()" } - XmlRole { name: "photoWidth"; query: "media:content/@width/string()" } - XmlRole { name: "photoHeight"; query: "media:content/@height/string()" } - XmlRole { name: "photoType"; query: "media:content/@type/string()" } - XmlRole { name: "photoAuthor"; query: "author/string()" } - XmlRole { name: "photoDate"; query: "pubDate/string()" } - } - - ListView { - clip: true - orientation: "Horizontal" - width: parent.width - height: 86 - y: 17 - model: feedModel - delegate: - Item { width: 90; height: 86 - Rectangle { - anchors.centerIn: parent - width: 86; height: 86; - color: "white"; radius: 5 - Image { source: imagePath; x: 5; y: 5 } - } - } - } -} - diff --git a/examples/declarative/flowview/RoundedRect.qml b/examples/declarative/flowview/RoundedRect.qml deleted file mode 100644 index 7d2b58b..0000000 --- a/examples/declarative/flowview/RoundedRect.qml +++ /dev/null @@ -1,4 +0,0 @@ -import Qt 4.6 - -Rectangle { radius: 5; border.width: 1; width:400; height: 120; color: background; } - diff --git a/examples/declarative/flowview/flowview.qml b/examples/declarative/flowview/flowview.qml deleted file mode 100644 index f6b042d..0000000 --- a/examples/declarative/flowview/flowview.qml +++ /dev/null @@ -1,147 +0,0 @@ -import Qt 4.6 - -Rectangle { - width: 800 - height: 800 - color: "black" - - Rectangle { - id: myPhone - transformOrigin: "Center" - anchors.centerIn: parent - width: 800 - height: 480 - clip: true - - states: State { - name: "rotated" - PropertyChanges { target: myListView; z: 2 } - PropertyChanges { target: topBar; y: -30 } - PropertyChanges { target: bottomBar; y: 480 } - PropertyChanges { target: leftBar; x: 0 } - PropertyChanges { target: rightBar; x: 770 } - } - transitions: Transition { - from: "" ; to: "rotated" - reversible: true - SequentialAnimation { - NumberAnimation { targets: [topBar, bottomBar]; properties: "x,y"; easing: "easeInOutQuad" } - NumberAnimation { targets: [leftBar, rightBar]; properties: "x,y"; easing: "easeInOutQuad"} - } - } - - color: "lightsteelblue" - - VisualDataModel { - id: model - model: ListModel { - ListElement { background: "red"; weblet: "RoundedRect.qml" } - ListElement { background: "yellow"; weblet: "RoundedRect.qml" } - ListElement { background: "blue"; weblet: "RoundedRect.qml" } - ListElement { background: "green"; weblet: "FlickrView.qml" } - ListElement { background: "orange"; weblet: "RoundedRect.qml" } - ListElement { background: "lightblue"; weblet: "RoundedRect.qml" } - } - delegate: Package { - Item { id: list; Package.name: "list"; width:120; height: 400; } - Item { id: gridItem; Package.name: "grid"; width:400; height: 120; } - Loader { id: myContent; width:400; height: 120; source: weblet } - - StateGroup { - states: [ - State { - name: "InList" - when: myPhone.state == "rotated" - ParentChange { target: myContent; parent: list } - PropertyChanges { target: myContent; x: 120; y: 0; rotation: 90} - }, - State { - name: "InGrid" - when: myPhone.state != "rotated" - ParentChange { target: myContent; parent: gridItem } - PropertyChanges { target: myContent; x: 0; y: 0; } - } - ] - transitions: [ - Transition { - from: "*"; to: "InGrid" - SequentialAnimation { - ParentAction{} - PauseAnimation { duration: 50 * list.FlowView.column } - NumberAnimation { properties: "x,y,rotation"; easing: "easeInOutQuad" } - } - }, - Transition { - from: "*"; to: "InList" - SequentialAnimation { - ParentAction{} - PauseAnimation { duration: 50 * (gridItem.FlowView.row * 2 + gridItem.FlowView.column) } - NumberAnimation { properties: "x,y,rotation"; easing: "easeInOutQuad" } - } - } - ] - } - - } - } - - Item { - FlowView { - id: myListView - vertical: true - y: 40 - x: 40 - width: 800 - height: 400 - column: 1 - model: model.parts.list - } - - FlowView { - z: 1 - y: 60 - width: 800 - height: 400 - column: 2 - model: model.parts.grid - } - } - - Rectangle { - id: topBar - width: 800 - height: 30 - } - Rectangle { - id: bottomBar - width: 800 - height: 30 - y: 450 - } - Rectangle { - id: leftBar - x: -30 - width: 30 - height: 480 - } - Rectangle { - id: rightBar - x: 800 - width: 30 - height: 480 - } - } - - Rectangle { - width: 80 - height: 80 - anchors.right: parent.right - anchors.bottom: parent.bottom - Text { text: "Switch" } - MouseRegion { - anchors.fill: parent - onClicked: if(myPhone.state == "rotated") myPhone.state=""; else myPhone.state = "rotated"; - } - } - -} diff --git a/src/declarative/extra/extra.pri b/src/declarative/extra/extra.pri index ae07a19..6730550 100644 --- a/src/declarative/extra/extra.pri +++ b/src/declarative/extra/extra.pri @@ -5,7 +5,6 @@ SOURCES += \ extra/qfxintegermodel.cpp \ extra/qmlfolderlistmodel.cpp \ extra/qfxanimatedimageitem.cpp \ - extra/qfxflowview.cpp \ extra/qfxparticles.cpp \ extra/qmlbehavior.cpp \ extra/qbindablemap.cpp \ @@ -19,7 +18,6 @@ HEADERS += \ extra/qmlfolderlistmodel.h \ extra/qfxanimatedimageitem.h \ extra/qfxanimatedimageitem_p.h \ - extra/qfxflowview.h \ extra/qfxparticles.h \ extra/qmlbehavior.h \ extra/qbindablemap.h \ diff --git a/src/declarative/extra/qfxflowview.cpp b/src/declarative/extra/qfxflowview.cpp deleted file mode 100644 index b2470ba..0000000 --- a/src/declarative/extra/qfxflowview.cpp +++ /dev/null @@ -1,379 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include "qfxvisualitemmodel.h" -#include "qfxflowview.h" - -#include - -QT_BEGIN_NAMESPACE - -class QFxFlowViewAttached : public QObject -{ -Q_OBJECT -Q_PROPERTY(int row READ row NOTIFY posChanged) -Q_PROPERTY(int column READ column NOTIFY posChanged) -public: - QFxFlowViewAttached(QObject *parent); - - int row() const; - int column() const; - -Q_SIGNALS: - void posChanged(); - -private: - friend class QFxFlowView; - int m_row; - int m_column; -}; - - -QFxFlowView::QFxFlowView() -: m_columns(0), m_model(0), m_vertical(false), m_dragItem(0), m_dragIdx(-1) -{ - setAcceptedMouseButtons(Qt::LeftButton); -} - -QFxVisualModel *QFxFlowView::model() const -{ - return m_model; -} - -void QFxFlowView::setModel(QFxVisualModel *m) -{ - m_model = m; - refresh(); -} - -int QFxFlowView::columns() const -{ - return m_columns; -} - -void QFxFlowView::setColumns(int c) -{ - m_columns = c; - refresh(); -} - -bool QFxFlowView::vertical() const -{ - return m_vertical; -} - -void QFxFlowView::setVertical(bool v) -{ - m_vertical = v; -} - -class QFxFlowViewValue : public QmlTimeLineValue -{ -public: - enum Property { xProperty, yProperty }; - - QFxFlowViewValue(QFxItem *item, Property p) - : m_item(item), m_property(p) {} - - qreal value() const { - return (m_property == xProperty)?m_item->x():m_item->y(); - } - void setValue(qreal v) { - if (m_property == xProperty) m_item->setX(v); - else m_item->setY(v); - } -private: - QFxItem *m_item; - Property m_property; -}; - -void QFxFlowView::refresh() -{ - if (m_model && m_columns >= 1) { - for (int ii = 0; ii < m_model->count(); ++ii) { - if (QFxItem *item = m_model->item(ii)) { - item->setParent(this); - item->setZValue(0); - m_items << item; - } - } - - reflow(); - } -} - -void QFxFlowView::reflow(bool animate) -{ - qreal y = 0; - qreal maxY = 0; - qreal x = 0; - int row = 0; - int column = -1; - if (animate) - clearTimeLine(); - - for (int ii = 0; ii < m_items.count(); ++ii) { - if (0 == (ii % m_columns)) { - y += maxY; - maxY = 0; - x = 0; - row = 0; - column++; - } - - QFxItem *item = m_items.at(ii); - QFxFlowViewAttached *att = - (QFxFlowViewAttached *)qmlAttachedPropertiesObject(item); - att->m_row = row; - att->m_column = column; - emit att->posChanged(); - - - if (animate) { - if (vertical()) - moveItem(item, QPointF(y, x)); - else - moveItem(item, QPointF(x, y)); - } else { - if (vertical()) { - item->setX(y); - item->setY(x); - } else { - item->setX(x); - item->setY(y); - } - } - if (vertical()) { - x += item->height(); - maxY = qMax(maxY, item->width()); - } else { - x += item->width(); - maxY = qMax(maxY, item->height()); - } - ++row; - } -} - -void QFxFlowView::reflowDrag(const QPointF &dp) -{ - qreal y = 0; - qreal maxY = 0; - qreal x = 0; - - clearTimeLine(); - - QList items; - - bool dragUsed = false; - bool dragSeen = false; - for (int ii = 0; ii < m_items.count(); ++ii) { - if (0 == (ii % m_columns)) { - y += maxY; - maxY = 0; - x = 0; - } - - QFxItem *item = m_items.at(ii); - if (item == m_dragItem) - dragSeen = true; - if (item == m_dragItem && dragUsed) - continue; - QRectF r; - if (vertical()) - r = QRectF(y, x, item->width(), item->height()); - else - r = QRectF(x, y, item->width(), item->height()); - if (r.contains(dp)) { - dragUsed = true; - if (dragSeen) - m_dragIdx = items.count() + 1; - else - m_dragIdx = items.count(); - - items.append(m_dragItem); - if (m_dragItem != item) { - if (dragSeen) - items.insert(items.count() - 1, item); - else - items.append(item); - } - } else { - if (m_dragItem != item) - items.append(item); - } - - if (vertical()) { - x += item->height(); - maxY = qMax(maxY, item->width()); - } else { - x += item->width(); - maxY = qMax(maxY, item->height()); - } - } - - y = 0; - maxY = 0; - x = 0; - clearTimeLine(); - for (int ii = 0; ii < items.count(); ++ii) { - if (0 == (ii % m_columns)) { - y += maxY; - maxY = 0; - x = 0; - } - - QFxItem *item = items.at(ii); - if (item != m_dragItem) { - if (vertical()) - moveItem(item, QPointF(y, x)); - else - moveItem(item, QPointF(x, y)); - } - if (vertical()) { - x += item->height(); - maxY = qMax(maxY, item->width()); - } else { - x += item->width(); - maxY = qMax(maxY, item->height()); - } - } - -} - -void QFxFlowView::moveItem(QFxItem *item, const QPointF &p) -{ - QFxFlowViewValue *xv = new QFxFlowViewValue(item, QFxFlowViewValue::xProperty); - QFxFlowViewValue *yv = new QFxFlowViewValue(item, QFxFlowViewValue::yProperty); - m_values << xv << yv; - m_timeline.move(*xv, p.x(), 100); - m_timeline.move(*yv, p.y(), 100); -} - -void QFxFlowView::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - for (int ii = 0; ii < m_items.count(); ++ii) { - QFxItem *item = m_items.at(ii); - QRectF r = rectForItem(ii); - - if (r.contains(event->pos())) { - m_dragItem = item; - m_dragItem->setZValue(1); - m_dragOffset = r.topLeft() - event->pos(); - event->accept(); - return; - } - } - event->ignore(); -} - -QRectF QFxFlowView::rectForItem(int idx) const -{ - QFxItem *item = m_items.at(idx); - QRectF r(item->x(), item->y(), item->width(), item->height()); - return r; -} - -void QFxFlowView::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - Q_UNUSED(event); - if (m_dragItem) { - m_dragItem->setZValue(0); - - clearTimeLine(); - - if (m_dragIdx != -1) { - m_items.removeAll(m_dragItem); - m_items.insert(m_dragIdx, m_dragItem); - } - - reflow(true); - m_dragItem = 0; - m_dragIdx = -1; - } -} - -QFxFlowViewAttached::QFxFlowViewAttached(QObject *parent) -: QObject(parent), m_row(0), m_column(0) -{ -} - -int QFxFlowViewAttached::row() const -{ - return m_row; -} - -int QFxFlowViewAttached::column() const -{ - return m_column; -} - -QFxFlowViewAttached *QFxFlowView::qmlAttachedProperties(QObject *obj) -{ - return new QFxFlowViewAttached(obj); -} - -void QFxFlowView::clearTimeLine() -{ - m_timeline.clear(); - qDeleteAll(m_values); - m_values.clear(); -} - -void QFxFlowView::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if (m_dragItem) { - QPointF p = event->pos() + m_dragOffset; - m_dragItem->setX(p.x()); - m_dragItem->setY(p.y()); - - for (int ii = 0; ii < m_items.count(); ++ii) { - if (m_items.at(ii) != m_dragItem && rectForItem(ii).contains(event->pos())) { - reflowDrag(event->pos()); - } - } - } -} - -QML_DEFINE_TYPE(Qt, 4,6, (QT_VERSION&0x00ff00)>>8, FlowView, QFxFlowView); - -QT_END_NAMESPACE - -#include "qfxflowview.moc" diff --git a/src/declarative/extra/qfxflowview.h b/src/declarative/extra/qfxflowview.h deleted file mode 100644 index 2d7a8bd..0000000 --- a/src/declarative/extra/qfxflowview.h +++ /dev/null @@ -1,108 +0,0 @@ -/**************************************************************************** -** -** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). -** Contact: Qt Software Information (qt-info@nokia.com) -** -** This file is part of the QtDeclarative module 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 either Technology Preview License Agreement or the -** Beta Release License Agreement. -** -** 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.0, included in the file LGPL_EXCEPTION.txt in this -** package. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.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 the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at qt-sales@nokia.com. -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#ifndef QFXFLOWVIEW_H -#define QFXFLOWVIEW_H - -#include -#include - -QT_BEGIN_HEADER - -QT_BEGIN_NAMESPACE - -QT_MODULE(Declarative) - -class QFxVisualModel; -class QFxFlowViewValue; -class QFxFlowViewAttached; -class Q_DECLARATIVE_EXPORT QFxFlowView : public QFxItem -{ - Q_OBJECT - Q_PROPERTY(QFxVisualModel *model READ model WRITE setModel) - Q_PROPERTY(int column READ columns WRITE setColumns) - Q_PROPERTY(bool vertical READ vertical WRITE setVertical) - -public: - QFxFlowView(); - - QFxVisualModel *model() const; - void setModel(QFxVisualModel *); - - int columns() const; - void setColumns(int); - - bool vertical() const; - void setVertical(bool); - - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - - static QFxFlowViewAttached *qmlAttachedProperties(QObject *); - -private: - QRectF rectForItem(int idx) const; - void refresh(); - void reflow(bool animate = false); - void reflowDrag(const QPointF &); - void clearTimeLine(); - int m_columns; - QFxVisualModel *m_model; - QList m_items; - bool m_vertical; - void moveItem(QFxItem *item, const QPointF &); - - QPointF m_dragOffset; - QFxItem *m_dragItem; - - QmlTimeLine m_timeline; - QList m_values; - int m_dragIdx; -}; - -QT_END_NAMESPACE - -QML_DECLARE_TYPE(QFxFlowView) - -QT_END_HEADER - -#endif // QFXFLOWVIEW_H -- cgit v0.12 From 5b77922f3782de4b96d6cf07ebb88419de130eac Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 7 Oct 2009 12:46:59 +1000 Subject: SameGame tutorial images --- doc/src/declarative/pics/declarative-adv-tutorial1.png | Bin 0 -> 81295 bytes doc/src/declarative/pics/declarative-adv-tutorial2.png | Bin 0 -> 170388 bytes doc/src/declarative/pics/declarative-adv-tutorial3.png | Bin 0 -> 220052 bytes doc/src/declarative/pics/declarative-adv-tutorial4.png | Bin 0 -> 273086 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 doc/src/declarative/pics/declarative-adv-tutorial1.png create mode 100644 doc/src/declarative/pics/declarative-adv-tutorial2.png create mode 100644 doc/src/declarative/pics/declarative-adv-tutorial3.png create mode 100644 doc/src/declarative/pics/declarative-adv-tutorial4.png diff --git a/doc/src/declarative/pics/declarative-adv-tutorial1.png b/doc/src/declarative/pics/declarative-adv-tutorial1.png new file mode 100644 index 0000000..990a329 Binary files /dev/null and b/doc/src/declarative/pics/declarative-adv-tutorial1.png differ diff --git a/doc/src/declarative/pics/declarative-adv-tutorial2.png b/doc/src/declarative/pics/declarative-adv-tutorial2.png new file mode 100644 index 0000000..b410d50 Binary files /dev/null and b/doc/src/declarative/pics/declarative-adv-tutorial2.png differ diff --git a/doc/src/declarative/pics/declarative-adv-tutorial3.png b/doc/src/declarative/pics/declarative-adv-tutorial3.png new file mode 100644 index 0000000..e192772 Binary files /dev/null and b/doc/src/declarative/pics/declarative-adv-tutorial3.png differ diff --git a/doc/src/declarative/pics/declarative-adv-tutorial4.png b/doc/src/declarative/pics/declarative-adv-tutorial4.png new file mode 100644 index 0000000..03c9f46 Binary files /dev/null and b/doc/src/declarative/pics/declarative-adv-tutorial4.png differ -- cgit v0.12 From 19d080d319dccac15654294af80530bed9ef11ea Mon Sep 17 00:00:00 2001 From: Alan Alpert Date: Wed, 7 Oct 2009 13:12:24 +1000 Subject: Switch Same Game tutorial to using snippets properly --- doc/src/declarative/advtutorial1.qdoc | 80 +--------- doc/src/declarative/advtutorial2.qdoc | 76 +--------- doc/src/declarative/advtutorial3.qdoc | 166 ++------------------- doc/src/declarative/advtutorial4.qdoc | 80 ++-------- .../declarative/pics/declarative-adv-tutorial4.gif | Bin 0 -> 58337629 bytes .../declarative/pics/declarative-adv-tutorial4.png | Bin 273086 -> 0 bytes .../tutorials/samegame/samegame1/Block.qml | 2 + .../tutorials/samegame/samegame1/Button.qml | 2 + .../tutorials/samegame/samegame1/samegame.qml | 2 + .../tutorials/samegame/samegame2/samegame.js | 2 + .../tutorials/samegame/samegame2/samegame.qml | 4 + .../tutorials/samegame/samegame3/Block.qml | 2 + .../tutorials/samegame/samegame3/Dialog.qml | 2 + .../tutorials/samegame/samegame3/samegame.js | 4 + .../tutorials/samegame/samegame3/samegame.qml | 6 + .../samegame/samegame4/content/BoomBlock.qml | 10 +- .../samegame/samegame4/content/samegame.js | 2 + 17 files changed, 73 insertions(+), 367 deletions(-) create mode 100644 doc/src/declarative/pics/declarative-adv-tutorial4.gif delete mode 100644 doc/src/declarative/pics/declarative-adv-tutorial4.png diff --git a/doc/src/declarative/advtutorial1.qdoc b/doc/src/declarative/advtutorial1.qdoc index b940986..48b32cd 100644 --- a/doc/src/declarative/advtutorial1.qdoc +++ b/doc/src/declarative/advtutorial1.qdoc @@ -10,46 +10,7 @@ The first step is to create the items in your application. In Same Game we have Here is the QML code for the basic elements. The game window: -\code -import Qt 4.6 - -Rectangle { - id: Screen - width: 490; height: 720 - - SystemPalette { id: activePalette; colorGroup: Qt.Active } - - Item { - width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top - - Image { - id: background - anchors.fill: parent; source: "pics/background.png" - fillMode: "PreserveAspectCrop" - } - } - - Rectangle { - id: ToolBar - color: activePalette.window - height: 32; width: parent.width - anchors.bottom: Screen.bottom - - Button { - id: btnA; text: "New Game"; onClicked: print("Implement me!"); - anchors.left: parent.left; anchors.leftMargin: 3 - anchors.verticalCenter: parent.verticalCenter - } - - Text { - id: Score - text: "Score: Who knows?"; font.bold: true - anchors.right: parent.right; anchors.rightMargin: 3 - anchors.verticalCenter: parent.verticalCenter - } - } -} -\endcode +\snippet declarative/tutorials/samegame/samegame1/samegame.qml 0 This gives you a basic game window, with room for the game canvas. A new game button and room to display the score. The one thing you may not recognize here @@ -59,49 +20,14 @@ feel you would use a QPushButton). Since we want a fully QML button, and the Fx primitives don't include a button, we had to write our own. Below is the code which we wrote to do this: -\code -import Qt 4.6 - -Rectangle { - id: Container - - signal clicked - property string text: "Button" - - color: activePalette.button; smooth: true - width: txtItem.width + 20; height: txtItem.height + 6 - border.width: 1; border.color: activePalette.darker(activePalette.button); radius: 8; - - gradient: Gradient { - GradientStop { - id: topGrad; position: 0.0 - color: if (mr.pressed) { activePalette.dark } else { activePalette.light } } - GradientStop { position: 1.0; color: activePalette.button } - } - - MouseRegion { id: mr; anchors.fill: parent; onClicked: Container.clicked() } +\snippet declarative/tutorials/samegame/samegame1/Button.qml 0 - Text { - id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText - } -} -\endcode Note that this Button component was written to be fairly generic, in case we want to use a similarly styled button later. And here is a simple block: -\code -import Qt 4.6 -Item { - id:block - - Image { id: img - source: "pics/redStone.png"; - anchors.fill: parent - } -} -\endcode +\snippet declarative/tutorials/samegame/samegame1/Block.qml 0 Since it doesn't do anything yet it's very simple, just an image. As the tutorial progresses and the block starts doing things the file will become diff --git a/doc/src/declarative/advtutorial2.qdoc b/doc/src/declarative/advtutorial2.qdoc index c17f9c4..2d2fe19 100644 --- a/doc/src/declarative/advtutorial2.qdoc +++ b/doc/src/declarative/advtutorial2.qdoc @@ -13,68 +13,7 @@ in the ECMA script, as opposed to using a Repeater. This adds enough script to justify a new file, samegame.js, the intial version of which is shown below -\code -//Note that X/Y referred to here are in game coordinates -var maxX = 10;//Nums are for tileSize 40 -var maxY = 15; -var tileSize = 40; -var maxIndex = maxX*maxY; -var board = new Array(maxIndex); -var tileSrc = "Block.qml"; -var component; - -//Index function used instead of a 2D array -function index(xIdx,yIdx) { - return xIdx + (yIdx * maxX); -} - -function initBoard() -{ - //Calculate board size - maxX = Math.floor(background.width/tileSize); - maxY = Math.floor(background.height/tileSize); - maxIndex = maxY*maxX; - - //Initialize Board - board = new Array(maxIndex); - for(xIdx=0; xIdx= maxX || xIdx < 0 || yIdx >= maxY || yIdx < 0) - return; - if(board[index(xIdx, yIdx)] == null) - return; - //If it's a valid tile, remove it and all connected (does nothing if it's not connected) - floodFill(xIdx,yIdx, -1); - if(fillFound <= 0) - return; - gameCanvas.score += (fillFound - 1) * (fillFound - 1); - shuffleDown(); - victoryCheck(); -} - -function victoryCheck() -{ - //awards bonuses for no tiles left - deservesBonus = true; - for(xIdx=maxX-1; xIdx>=0; xIdx--) - if(board[index(xIdx, maxY - 1)] != null) - deservesBonus = false; - if(deservesBonus) - gameCanvas.score += 500; - //Checks for game over - if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))) - dialog.show("Game Over. Your score is " + gameCanvas.score); -} -\endcode +\snippet declarative/tutorials/samegame/samegame3/samegame.js 1 +\snippet declarative/tutorials/samegame/samegame3/samegame.js 2 You'll notice them referring to the 'gameCanvas' item. This is an item that has been added to the QML for easy interfacing. It is placed next to the background image and replaces the background as the item to create the blocks in. Its code is shown below: -\code - Item { - id: gameCanvas - property int score: 0 - property int tileSize: 40 - - z: 20; anchors.centerIn: parent - width: parent.width - (parent.width % tileSize); - height: parent.height - (parent.height % tileSize); - - MouseRegion { - id: gameMR - anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); - } - } -\endcode + +\snippet declarative/tutorials/samegame/samegame3/samegame.qml 1 This item is the exact size of the board, contains a score property, and a mouse region for input. The blocks are now created as its children, and its size is used as the noe determining board size. Since it needs to bind its size to a multiple of tileSize, tileSize needs to be moved into a QML property and out of the script file. It can still be accessed from the script. The mouse region simply calls handleClick(), which deals with the input events.Should those events cause the player to score, gameCanvas.score is updated. The score display text item has also been changed to bind its text property to gamecanvas.score. Note that if score was a global variable in the samegame.js file yo ucould not bind to it. You can only bind to QML properties. victoryCheck() mostly just updates score. But it also pops up a dialog saying 'Game Over' when the game is over. In this example we wanted a pure-QML, animated dialog, and since the Fx primitives set doesn't contain one, we wrote our own. Below is the code for the Dialog element, note how it's designed so as to be quite usable imperatively from within the script file: -\code -import Qt 4.6 - -Rectangle { - id: page - function forceClose() { - page.closed(); - page.opacity = 0; - } - function show(txt) { - MyText.text = txt; - page.opacity = 1; - } - signal closed(); - color: "white"; border.width: 1; width: MyText.width + 20; height: 60; - opacity: 0 - opacity: Behavior { - NumberAnimation { duration: 1000 } - } - Text { id: MyText; anchors.centerIn: parent; text: "Hello World!" } - MouseRegion { id: mr; anchors.fill: parent; onClicked: forceClose(); } -} -\endcode + +\snippet declarative/tutorials/samegame/samegame3/Dialog.qml 0 + And this is how it's used in the main QML file: -\code - Dialog { id: dialog; anchors.centerIn: parent; z: 21 } -\endcode + +\snippet declarative/tutorials/samegame/samegame3/samegame.qml 2 + Combined with the line of code in victoryCheck, this causes a dialog to appear when the game is over, informing the user of that fact. We now have a working game! The blocks can be clicked, the player can score, and the game can end (and then you start a new one). Below is a screenshot of what has been accomplished so far: @@ -107,87 +43,11 @@ We now have a working game! The blocks can be clicked, the player can score, and Here is the QML code as it is now for the main file: -\code -import Qt 4.6 - -Rectangle { - id: Screen - width: 490; height: 720 - - SystemPalette { id: activePalette; colorGroup: Qt.Active } - Script { source: "samegame.js" } - - Item { - width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top - - Image { - id: background - anchors.fill: parent; source: "pics/background.png" - fillMode: "PreserveAspectCrop" - } - - Item { - id: gameCanvas - property int score: 0 - property int tileSize: 40 - - z: 20; anchors.centerIn: parent - width: parent.width - (parent.width % tileSize); - height: parent.height - (parent.height % tileSize); - - MouseRegion { - id: gameMR - anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); - } - } - } - - Dialog { id: dialog; anchors.centerIn: parent; z: 21 } - - Rectangle { - id: ToolBar - color: activePalette.window - height: 32; width: parent.width - anchors.bottom: Screen.bottom - - Button { - id: btnA; text: "New Game"; onClicked: initBoard(); - anchors.left: parent.left; anchors.leftMargin: 3 - anchors.verticalCenter: parent.verticalCenter - } - - Text { - id: Score - text: "Score: " + gameCanvas.score; font.bold: true - anchors.right: parent.right; anchors.rightMargin: 3 - anchors.verticalCenter: parent.verticalCenter - } - } -} -\endcode +\snippet declarative/tutorials/samegame/samegame3/samegame.qml 0 And the code for the block: -\code -import Qt 4.6 - -Item { - id:block - property int type: 0 - - Image { id: img - source: { - if(type == 0){ - "pics/redStone.png"; - } else if(type == 1) { - "pics/blueStone.png"; - } else { - "pics/greenStone.png"; - } - } - anchors.fill: parent - } -} -\endcode + +\snippet declarative/tutorials/samegame/samegame3/Block.qml 0 The game works, but it's a little boring right now. Where's the smooth animated transitions? Where's the high scores? If you were a QML expert you could have written these in for the first iteration, but in this tutorial they've been saved until the next chapter - where your application becomes alive! diff --git a/doc/src/declarative/advtutorial4.qdoc b/doc/src/declarative/advtutorial4.qdoc index 5ad1ec3..291d2f2 100644 --- a/doc/src/declarative/advtutorial4.qdoc +++ b/doc/src/declarative/advtutorial4.qdoc @@ -10,6 +10,7 @@ If you compare the samegame3 directory with samegame4, you'll noticed that we've \section2 Animated Blocks The most vital animations are that the blocks move fluidly around the board. QML has many tools for fluid behavior, and in this case we're going to use the Follow element. By having the script set targetX and targetY, instead of x and y directly, we can set the x and y of the block to a follow. SpringFollow is a property value source, which means that you can set a property to be one of these elements and it will automatically bind the property to the element's value. The SpringFollow's value follows another value over time, when the value it is tracking changes the SpringFollow's value will also change, but it will move smoothly there over time with a spring-like movement (based on the spring parameters specified). This is shown in the below snippet of code from Block.qml: + \code property int targetX: 0 property int targetY: 0 @@ -20,32 +21,11 @@ The most vital animations are that the blocks move fluidly around the board. QML We also have to change the samegame.js code, so that wherever it was setting the x or y it now sets targetX and targetY (including when creating the block). This simple change is all you need to get spring moving blocks that no longer teleport around the board. If you try doing just this though, you'll notice that they now never jump from one point to another, even in the initialization! This gives an odd effect of having them all jump out of the corner (0,0) on start up. We'd rather that they fall down from the top in rows. To do this, we disable the x Follow (but not the y follow) and only enable it after we've set the x in the createBlock function. The above snippet now becomes: -\code - property bool spawned: false - property int targetX: 0 - property int targetY: 0 - - x: SpringFollow { enabled: spawned; source: targetX; spring: 2; damping: 0.2 } - y: SpringFollow { source: targetY; spring: 2; damping: 0.2 } -\endcode +\snippet declarative/tutorials/samegame/samegame4/content/BoomBlock.qml 1 The next-most vital animation is a smooth exit. For this animation, we'll use a Behavior element. A Behavior is also a property value source, and it is much like SpringFollow except that it doesn't model the behavior of a spring. You specify how a Behavior transitions using the standard animations. As we want the blocks to smoothly fade in and out we'll set a Behavior on the block image's opacity, like so: -\code - Image { id: img - source: { - if(type == 0){ - "pics/redStone.png"; - } else if(type == 1) { - "pics/blueStone.png"; - } else { - "pics/greenStone.png"; - } - } - opacity: 0 - opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } - anchors.fill: parent - } -\endcode + +\snippet declarative/tutorials/samegame/samegame4/content/BoomBlock.qml 2 Note that the 'opacity: 0' makes it start out transparent. We could set the opacity in the script file when we create the blocks, but instead we use states (as this is useful for the next animation we'll implement). The below snippet is set on the root element of Block.qml: \code @@ -62,53 +42,25 @@ Note that the 'opacity: 0' makes it start out transparent. We could set the opac Now it will automatically fade in, as we set spawned to true already when implementing the block movement animations. To fade out, we set 'dying' to true instead of setting opacity to 0 when a block is destroyed (in the floodFill function). The least vital animations are a cool-looking particle effect when they get destroyed. First we create a Particles Element in the block, like so: -\code - Particles { id: particles - width:1; height:1; anchors.centerIn: parent; opacity: 0 - lifeSpan: 700; lifeSpanDeviation: 600; count:0; streamIn: false - angle: 0; angleDeviation: 360; velocity: 100; velocityDeviation:30 - source: { - if(type == 0){ - "pics/redStar.png"; - } else if (type == 1) { - "pics/blueStar.png"; - } else { - "pics/greenStar.png"; - } - } - } -\endcode + +\snippet declarative/tutorials/samegame/samegame4/content/BoomBlock.qml 3 + To fully understand this you'll want to look at the Particles element documentation, but it's important to note that count is set to zero. -We next extend the 'dying' state, which triggers the particles by setting the count to non-zero. The code for that state looks like this: -\code - State{ name: "DeathState"; when: dying == true - PropertyChanges { target: particles; count: 50 } - PropertyChanges { target: particles; opacity: 1 } - PropertyChanges { target: particles; emitting: false } // i.e. emit only once - PropertyChanges { target: img; opacity: 0 } - } -\endcode -And now the game should be beautifully animated and smooth, with a subtle (or not-so-subtle) animation added for all of the player's actions. +We next extend the 'dying' state, which triggers the particles by setting the count to non-zero. The code for the states now look like this: + +\snippet declarative/tutorials/samegame/samegame4/content/BoomBlock.qml 4 + +And now the game should be beautifully animated and smooth, with a subtle (or not-so-subtle) animation added for all of the player's actions. The end result is shown below: + +\image declarative-adv-tutorial4.gif \section2 Web-based High Scores Another extension we might want for the game is some way of storing and retriveing high scores. In this tutorial we'll show you how to integrate a web enabled high score storage into your QML application. The implementation we've done is very simple - the high score data is posted to a php script running on a server somewhere, and that server then stores it and displays it to visitors. You could request an XML or QML file from that same server, which contained and displayed the scores, but that's beyond the scope of this tutorial. For better high score data, we want the name and time of the player. The time is obtained in the script fairly simply, but we have to ask the player for their name. We thus re-use the dialog QML file to pop up a dialog asking for the player's name (and if they exit this dialog without entering it they have a way to opt out of posting their high score). When the dialog is closed, if the player entered their name we can send the data to the web service in the followign snippet out of the script file: -\code -function sendHighScore(name) { - var postman = new XMLHttpRequest() - var postData = "name="+name+"&score="+gameCanvas.score - +"&gridSize="+maxX+"x"+maxY +"&time="+Math.floor(timer/1000); - postman.open("POST", scoresURL, true); - postman.onreadystatechange = function() { - if (postman.readyState == postman.DONE) { - dialog.show("Your score has been uploaded."); - } - } - postman.send(postData); -} -\endcode + +\snippet declarative/tutorials/samegame/samegame4/content/samegame.js 1 This is the same XMLHttpRequest() as you'll find in browser javascript, and can be used in the same way to dynamically get XML or QML from the web service to display the high scores. We don't worry about the response here though, we just post the high score data to the web server. If it had returned a QML file (or a URL to a QML file) you could instantiate it in much the same way as you did the blocks. diff --git a/doc/src/declarative/pics/declarative-adv-tutorial4.gif b/doc/src/declarative/pics/declarative-adv-tutorial4.gif new file mode 100644 index 0000000..a67666d Binary files /dev/null and b/doc/src/declarative/pics/declarative-adv-tutorial4.gif differ diff --git a/doc/src/declarative/pics/declarative-adv-tutorial4.png b/doc/src/declarative/pics/declarative-adv-tutorial4.png deleted file mode 100644 index 03c9f46..0000000 Binary files a/doc/src/declarative/pics/declarative-adv-tutorial4.png and /dev/null differ diff --git a/examples/declarative/tutorials/samegame/samegame1/Block.qml b/examples/declarative/tutorials/samegame/samegame1/Block.qml index 228ac4e..b76e61a 100644 --- a/examples/declarative/tutorials/samegame/samegame1/Block.qml +++ b/examples/declarative/tutorials/samegame/samegame1/Block.qml @@ -1,3 +1,4 @@ +//![0] import Qt 4.6 Item { @@ -8,3 +9,4 @@ Item { anchors.fill: parent } } +//![0] diff --git a/examples/declarative/tutorials/samegame/samegame1/Button.qml b/examples/declarative/tutorials/samegame/samegame1/Button.qml index 2354218..3846cf7 100644 --- a/examples/declarative/tutorials/samegame/samegame1/Button.qml +++ b/examples/declarative/tutorials/samegame/samegame1/Button.qml @@ -1,3 +1,4 @@ +//![0] import Qt 4.6 Rectangle { @@ -23,3 +24,4 @@ Rectangle { id: txtItem; text: Container.text; anchors.centerIn: Container; color: activePalette.buttonText } } +//![0] diff --git a/examples/declarative/tutorials/samegame/samegame1/samegame.qml b/examples/declarative/tutorials/samegame/samegame1/samegame.qml index d18718d..8b32cae 100644 --- a/examples/declarative/tutorials/samegame/samegame1/samegame.qml +++ b/examples/declarative/tutorials/samegame/samegame1/samegame.qml @@ -1,3 +1,4 @@ +//![0] import Qt 4.6 Rectangle { @@ -36,3 +37,4 @@ Rectangle { } } } +//![0] diff --git a/examples/declarative/tutorials/samegame/samegame2/samegame.js b/examples/declarative/tutorials/samegame/samegame2/samegame.js index 064d87e..2bf68b5 100644 --- a/examples/declarative/tutorials/samegame/samegame2/samegame.js +++ b/examples/declarative/tutorials/samegame/samegame2/samegame.js @@ -1,3 +1,4 @@ +//![0] //Note that X/Y referred to here are in game coordinates var maxX = 10;//Nums are for tileSize 40 var maxY = 15; @@ -57,3 +58,4 @@ function createBlock(xIdx,yIdx){ } return true; } +//![0] diff --git a/examples/declarative/tutorials/samegame/samegame2/samegame.qml b/examples/declarative/tutorials/samegame/samegame2/samegame.qml index e446fa4..78a3d83 100644 --- a/examples/declarative/tutorials/samegame/samegame2/samegame.qml +++ b/examples/declarative/tutorials/samegame/samegame2/samegame.qml @@ -5,7 +5,9 @@ Rectangle { width: 490; height: 720 SystemPalette { id: activePalette; colorGroup: Qt.Active } + //![2] Script { source: "samegame.js" } + //![2] Item { width: parent.width; anchors.top: parent.top; anchors.bottom: ToolBar.top @@ -23,11 +25,13 @@ Rectangle { height: 32; width: parent.width anchors.bottom: Screen.bottom + //![1] Button { id: btnA; text: "New Game"; onClicked: initBoard(); anchors.left: parent.left; anchors.leftMargin: 3 anchors.verticalCenter: parent.verticalCenter } + //![1] Text { id: Score diff --git a/examples/declarative/tutorials/samegame/samegame3/Block.qml b/examples/declarative/tutorials/samegame/samegame3/Block.qml index 2f28923..30a8d3a 100644 --- a/examples/declarative/tutorials/samegame/samegame3/Block.qml +++ b/examples/declarative/tutorials/samegame/samegame3/Block.qml @@ -1,3 +1,4 @@ +//![0] import Qt 4.6 Item { @@ -17,3 +18,4 @@ Item { anchors.fill: parent } } +//![0] diff --git a/examples/declarative/tutorials/samegame/samegame3/Dialog.qml b/examples/declarative/tutorials/samegame/samegame3/Dialog.qml index 401d211..5fe6aa0 100644 --- a/examples/declarative/tutorials/samegame/samegame3/Dialog.qml +++ b/examples/declarative/tutorials/samegame/samegame3/Dialog.qml @@ -1,3 +1,4 @@ +//![0] import Qt 4.6 Rectangle { @@ -19,3 +20,4 @@ Rectangle { Text { id: MyText; anchors.centerIn: parent; text: "Hello World!" } MouseRegion { id: mr; anchors.fill: parent; onClicked: forceClose(); } } +//![0] diff --git a/examples/declarative/tutorials/samegame/samegame3/samegame.js b/examples/declarative/tutorials/samegame/samegame3/samegame.js index 16b349d..8fecfef 100644 --- a/examples/declarative/tutorials/samegame/samegame3/samegame.js +++ b/examples/declarative/tutorials/samegame/samegame3/samegame.js @@ -72,6 +72,7 @@ function createBlock(xIdx,yIdx){ var fillFound;//Set after a floodFill call to the number of tiles found var floodBoard;//Set to 1 if the floodFill reaches off that node //NOTE: Be careful with vars named x,y, as the calling object's x,y are still in scope +//![1] function handleClick(x,y) { xIdx = Math.floor(x/gameCanvas.tileSize); @@ -88,6 +89,7 @@ function handleClick(x,y) shuffleDown(); victoryCheck(); } +//![1] function floodFill(xIdx,yIdx,type) { @@ -156,6 +158,7 @@ function shuffleDown() } } +//![2] function victoryCheck() { //awards bonuses for no tiles left @@ -169,6 +172,7 @@ function victoryCheck() if(deservesBonus || !(floodMoveCheck(0,maxY-1, -1))) dialog.show("Game Over. Your score is " + gameCanvas.score); } +//![2] //only floods up and right, to see if it can find adjacent same-typed tiles function floodMoveCheck(xIdx, yIdx, type) diff --git a/examples/declarative/tutorials/samegame/samegame3/samegame.qml b/examples/declarative/tutorials/samegame/samegame3/samegame.qml index ea43ab2..a0883da 100644 --- a/examples/declarative/tutorials/samegame/samegame3/samegame.qml +++ b/examples/declarative/tutorials/samegame/samegame3/samegame.qml @@ -1,3 +1,4 @@ +//![0] import Qt 4.6 Rectangle { @@ -16,6 +17,7 @@ Rectangle { fillMode: "PreserveAspectCrop" } + //![1] Item { id: gameCanvas property int score: 0 @@ -30,9 +32,12 @@ Rectangle { anchors.fill: parent; onClicked: handleClick(mouse.x,mouse.y); } } + //![1] } + //![2] Dialog { id: dialog; anchors.centerIn: parent; z: 21 } + //![2] Rectangle { id: ToolBar @@ -54,3 +59,4 @@ Rectangle { } } } +//![0] diff --git a/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml b/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml index a495cd0..7ad8b07 100644 --- a/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml +++ b/examples/declarative/tutorials/samegame/samegame4/content/BoomBlock.qml @@ -1,15 +1,18 @@ import Qt 4.6 Item { id:block + property int type: 0 property bool dying: false + //![1] property bool spawned: false - property int type: 0 property int targetX: 0 property int targetY: 0 x: SpringFollow { enabled: spawned; source: targetX; spring: 2; damping: 0.2 } y: SpringFollow { source: targetY; spring: 2; damping: 0.2 } + //![1] + //![2] Image { id: img source: { if(type == 0){ @@ -24,7 +27,9 @@ Item { id:block opacity: Behavior { NumberAnimation { properties:"opacity"; duration: 200 } } anchors.fill: parent } + //![2] + //![3] Particles { id: particles width:1; height:1; anchors.centerIn: parent; opacity: 0 lifeSpan: 700; lifeSpanDeviation: 600; count:0; streamIn: false @@ -39,7 +44,9 @@ Item { id:block } } } + //![3] + //![4] states: [ State{ name: "AliveState"; when: spawned == true && dying == false PropertyChanges { target: img; opacity: 1 } @@ -51,4 +58,5 @@ Item { id:block PropertyChanges { target: img; opacity: 0 } } ] + //![4] } diff --git a/examples/declarative/tutorials/samegame/samegame4/content/samegame.js b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js index cf55b59..ce9c169 100755 --- a/examples/declarative/tutorials/samegame/samegame4/content/samegame.js +++ b/examples/declarative/tutorials/samegame/samegame4/content/samegame.js @@ -203,6 +203,7 @@ function createBlock(xIdx,yIdx){ return true; } +//![1] function sendHighScore(name) { var postman = new XMLHttpRequest() var postData = "name="+name+"&score="+gameCanvas.score @@ -215,3 +216,4 @@ function sendHighScore(name) { } postman.send(postData); } +//![1] -- cgit v0.12