main.qml 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516
  1. /**
  2. * Copyright (c) 2011 Nokia Corporation.
  3. */
  4. import QtQuick 1.0
  5. import 'gameLogic.js' as Functions
  6. // The type of the AppWindow depends on the build; e.g. in Symbian and Maemo 5
  7. // AppWindow is actually a regular Item QML element. In Harmattan build,
  8. // AppWindow is Window Qt component.
  9. AppWindow {
  10. id: main
  11. signal freeCellsReseted()
  12. signal boardChanged()
  13. property int blockDim: Functions.BLOCK_DIM
  14. property int blocksPerSide: Functions.BLOCKS_PER_SIDE
  15. property int dim: Functions.DIM
  16. property int moves: 0
  17. property int empties: 0
  18. property int time: 0
  19. property bool gameOn: false
  20. property bool portrait: true
  21. // The interface for the cells to the gameLogic.js.
  22. function resetNumber(index)
  23. {
  24. Functions.numbers[index] = 0;
  25. empties++;
  26. }
  27. function setSelectedNumber()
  28. {
  29. var cell = mainBoard.currentItem.currentItem;
  30. if (cell && cell.free)
  31. if(Functions.setNumberByUser(cell.cellIdx, viewLoader.item.selectedNumber))
  32. cell.number = viewLoader.item.selectedNumber ? viewLoader.item.selectedNumber : "";
  33. }
  34. function getNumber(index)
  35. {
  36. return Functions.numbers[index];
  37. }
  38. function win()
  39. {
  40. mainTimer.stop();
  41. gameOn = false;
  42. viewLoader.switchTo("WinNote.qml", viewLoader.initX, viewLoader.initY);
  43. }
  44. function reset()
  45. {
  46. freeCellsReseted();
  47. moves = 0;
  48. time = 0;
  49. mainTimer.start();
  50. }
  51. function newGame()
  52. {
  53. moves = 0;
  54. time = 0;
  55. puzzleWorker.sendMessage({});
  56. }
  57. function getFormattedTime(pTime)
  58. {
  59. var minFirstDigits = Math.floor(pTime/600);
  60. var secFirstDigits = Math.floor(pTime/10);
  61. var formattedTime = minFirstDigits + "" +
  62. (Math.floor(pTime/60)-minFirstDigits*10) + ":" +
  63. secFirstDigits%6 + "" + (pTime-secFirstDigits*10);
  64. return formattedTime;
  65. }
  66. function startCollisionAnimations(indices)
  67. {
  68. var prevBlockIdx = mainBoard.currentIndex;
  69. var prevIdx = mainBoard.currentItem.currentIndex;
  70. var idx;
  71. for (var i = 0; i < indices.length; i++) {
  72. idx = indices[i];
  73. var row = Math.floor(idx/dim);
  74. var column = idx%dim;
  75. var blockRow = Math.floor(row/blockDim);
  76. var blockColumn = Math.floor(column/blockDim);
  77. var rowInBlock = row - blockDim*blockRow;
  78. var colInBlock = column - blockDim*blockColumn;
  79. var blockIndex = blockRow*blocksPerSide+blockColumn;
  80. var indexInBlock = rowInBlock*blockDim+colInBlock;
  81. mainBoard.currentIndex = blockIndex;
  82. mainBoard.currentItem.currentIndex = indexInBlock;
  83. mainBoard.currentItem.currentItem.startCollisionAnimation();
  84. }
  85. mainBoard.currentIndex = prevBlockIdx;
  86. mainBoard.currentItem.currentIndex = prevIdx;
  87. }
  88. anchors.fill: parent
  89. onEmptiesChanged: {
  90. if (!empties)
  91. win();
  92. }
  93. Image {
  94. anchors.fill: parent
  95. source: "gfx/background.png"
  96. onHeightChanged: {
  97. main.portrait = (width < height);
  98. console.debug("main.qml:Image:onHeightChanged(): [", width, ",", height, "], portrait ==", portrait);
  99. }
  100. }
  101. WorkerScript {
  102. id: puzzleWorker
  103. source: "gameLogic.js"
  104. onMessage: {
  105. Functions.numbers = messageObject.board;
  106. empties = messageObject.boardEmpties;
  107. boardChanged();
  108. viewLoader.close();
  109. gameOn = true;
  110. mainBoard.focus = true;
  111. mainTimer.start();
  112. }
  113. }
  114. Timer {
  115. id: mainTimer
  116. interval: 1000
  117. repeat: true
  118. onTriggered: time++
  119. }
  120. Image {
  121. id: topic
  122. width: portrait ? sourceSize.width : statistics.width
  123. height: 0.25 * width
  124. source: "gfx/logo.png"
  125. anchors {
  126. top: parent.top
  127. topMargin: portrait ? parent.height * 0.02 : statistics.y - height - 10
  128. left: parent.left
  129. leftMargin: portrait ? parent.width / 2 - width / 2 : 10
  130. }
  131. }
  132. GridView {
  133. id: mainBoard
  134. property int currentBlockRow: Math.floor(currentIndex / blocksPerSide);
  135. property int currentBlockCol: currentIndex - currentBlockRow * blocksPerSide;
  136. width: portrait ? parent.width : parent.height
  137. height: width
  138. cellWidth: width / 3 - 3
  139. cellHeight: cellWidth
  140. boundsBehavior: Flickable.StopAtBounds
  141. anchors {
  142. topMargin: portrait ? (parent.height - height) / 2
  143. - topic.height - parent.height * 0.04 : 10;
  144. top: portrait ? topic.bottom : parent.top
  145. leftMargin: 5
  146. left: portrait ? parent.left : topic.right
  147. }
  148. delegate: Block {
  149. cellWidth: portrait ? mainBoard.width / dim - 2 : mainBoard.height / dim - 2
  150. cellHeight: cellWidth
  151. blockIdx: index;
  152. blockRow: Math.floor(blockIdx / blocksPerSide);
  153. blockCol: blockIdx - blockRow * blocksPerSide;
  154. currentRowInBlock: Math.floor(mainBoard.currentItem.currentIndex / blockDim);
  155. currentColInBlock: mainBoard.currentItem.currentIndex - currentRowInBlock * blockDim;
  156. isAtCurrentRow: Math.floor(index/blocksPerSide) == mainBoard.currentBlockRow;
  157. isAtCurrentCol: index - Math.floor(index / blocksPerSide) * blocksPerSide ==
  158. mainBoard.currentBlockCol;
  159. onChangingBlockToLeft: {
  160. if (mainBoard.currentBlockCol != 0) {
  161. var prevIdx = mainBoard.currentItem.currentIndex;
  162. mainBoard.currentIndex--;
  163. mainBoard.currentItem.currentIndex = prevIdx + blockDim-1;
  164. }
  165. else {
  166. var prevIdx = mainBoard.currentItem.currentIndex;
  167. mainBoard.currentIndex += blocksPerSide-1;
  168. mainBoard.currentItem.currentIndex = prevIdx + blockDim-1;
  169. }
  170. }
  171. onChangingBlockToRight: {
  172. if (mainBoard.currentBlockCol != blocksPerSide-1) {
  173. var prevIdx = mainBoard.currentItem.currentIndex;
  174. mainBoard.currentIndex++;
  175. mainBoard.currentItem.currentIndex = prevIdx - (blockDim-1);
  176. }
  177. else {
  178. var prevIdx = mainBoard.currentItem.currentIndex;
  179. mainBoard.currentIndex -= blocksPerSide-1;
  180. mainBoard.currentItem.currentIndex = prevIdx - (blockDim-1);
  181. }
  182. }
  183. }
  184. model: 9
  185. Keys.onPressed: {
  186. if (event.key == Qt.Key_Up) {
  187. if (currentBlockRow != 0) {
  188. var prevIdx = currentItem.currentIndex;
  189. currentIndex = currentIndex - blocksPerSide;
  190. currentItem.currentIndex = prevIdx + blockDim*(blockDim-1);
  191. event.accepted = true;
  192. }
  193. else {
  194. var prevIdx = currentItem.currentIndex;
  195. currentIndex = currentIndex + blocksPerSide*(blocksPerSide-1);
  196. currentItem.currentIndex = prevIdx + blockDim*(blockDim-1);
  197. event.accepted = true;
  198. }
  199. }
  200. if (event.key == Qt.Key_Down) {
  201. if (currentBlockRow != 2) {
  202. var prevIdx = currentItem.currentIndex;
  203. currentIndex = currentIndex + blocksPerSide;
  204. currentItem.currentIndex = prevIdx - blockDim*(blockDim-1);
  205. event.accepted = true;
  206. }
  207. else {
  208. var prevIdx = currentItem.currentIndex;
  209. currentIndex = currentIndex - blocksPerSide*(blocksPerSide-1);
  210. currentItem.currentIndex = prevIdx - blockDim*(blockDim-1);
  211. event.accepted = true;
  212. }
  213. }
  214. if (event.key == Qt.Key_Select || event.key == Qt.Key_Return ||
  215. event.key == Qt.Key_Enter) {
  216. boardMouseArea.clicked(0);
  217. event.accepted = true;
  218. }
  219. }
  220. }
  221. MouseArea {
  222. id: boardMouseArea
  223. property int blockDim: width/blocksPerSide+1
  224. function resetSelection() {
  225. mainBoard.currentIndex = blocksPerSide * blocksPerSide / 2 - 1;
  226. mainBoard.currentItem.currentIndex = main.blockDim * main.blockDim / 2-1;
  227. }
  228. anchors {
  229. bottomMargin: 12
  230. rightMargin: 12
  231. fill: mainBoard
  232. }
  233. Component.onCompleted: resetSelection();
  234. onPressed: positionChanged(mouse);
  235. onPositionChanged: {
  236. if (0 < mouseX && 0 < mouseY && mouseX < width && mouseY < height) {
  237. var prevBlockIdx = mainBoard.currentIndex;
  238. var prevIdx = mainBoard.currentItem.currentIndex;
  239. mainBoard.currentIndex = mainBoard.indexAt(mouseX, mouseY);
  240. if (mainBoard.currentItem) {
  241. mainBoard.currentItem.currentIndex =
  242. mainBoard.currentItem.indexAt(
  243. mouseX - Math.floor(mouseX / blockDim) * blockDim,
  244. mouseY - Math.floor(mouseY / blockDim) * blockDim);
  245. if (!mainBoard.currentItem.currentItem) {
  246. mainBoard.currentIndex = prevBlockIdx;
  247. mainBoard.currentItem.currentIndex = prevIdx;
  248. }
  249. }
  250. }
  251. else
  252. resetSelection();
  253. }
  254. onClicked: {
  255. if (mainBoard.currentItem.currentItem &&
  256. mainBoard.currentItem.currentItem.free) {
  257. viewLoader.switchTo("NumberPad.qml",
  258. x + mainBoard.currentItem.x
  259. + mainBoard.currentItem.currentItem.x,
  260. y + mainBoard.currentItem.y
  261. + mainBoard.currentItem.currentItem.y);
  262. }
  263. }
  264. }
  265. Image {
  266. id: statistics
  267. property int imageSize: 20
  268. source: "gfx/statistic.png"
  269. width: portrait ? parent.width * 0.4 : parent.height * 0.4
  270. height: width * 0.9
  271. anchors {
  272. bottom: parent.bottom
  273. bottomMargin: portrait ? 5 : 100
  274. left: parent.left
  275. leftMargin: portrait ? parent.width / 2 - width / 2 : 10
  276. }
  277. Column {
  278. anchors.centerIn: parent
  279. spacing: parent.height * 0.08
  280. Row {
  281. spacing: 10
  282. Image {
  283. width: statistics.imageSize
  284. height: statistics.imageSize
  285. source: "gfx/move.png"
  286. }
  287. Text {
  288. text: moves
  289. font.pixelSize: main.smallFontPixelSize
  290. font.family: "series 60 zdigi"
  291. }
  292. }
  293. Row {
  294. spacing: 10
  295. Image {
  296. width: statistics.imageSize
  297. height: statistics.imageSize
  298. source: "gfx/empty.png"
  299. }
  300. Text {
  301. text: empties
  302. font.pixelSize: main.smallFontPixelSize
  303. font.family: "series 60 zdigi"
  304. }
  305. }
  306. Row {
  307. spacing: 10
  308. Image {
  309. width: statistics.imageSize
  310. height: statistics.imageSize
  311. source: "gfx/time.png"
  312. }
  313. Text {
  314. text: getFormattedTime(time);
  315. font.pixelSize: main.smallFontPixelSize
  316. font.family: "series 60 zdigi"
  317. }
  318. }
  319. }
  320. }
  321. Text {
  322. id: optionsButton
  323. function click() {
  324. mainTimer.stop();
  325. viewLoader.switchTo("Menu.qml", x+width/2,
  326. y-height/2);
  327. }
  328. function press() {
  329. scale = 0.9
  330. color = "lightgray"
  331. }
  332. function release() {
  333. scale = 1
  334. color = "#ffffff"
  335. }
  336. anchors {
  337. left: parent.left
  338. leftMargin: 5
  339. bottom: parent.bottom
  340. bottomMargin: 5
  341. }
  342. text: "Options"
  343. font.pixelSize: main.largeFontPixelSize
  344. color: parent.focus ? "black" : "#ffffff"
  345. MouseArea {
  346. id: optionsMouseArea
  347. anchors.fill: parent
  348. onPressed: parent.press();
  349. onReleased: parent.release();
  350. onClicked: parent.click();
  351. }
  352. }
  353. Keys.onPressed: {
  354. if (!viewLoader.focus) {
  355. if (event.key == Qt.Key_Context1) {
  356. optionsButton.press();
  357. event.accepted = true;
  358. }
  359. if (event.key == Qt.Key_Context2) {
  360. exitButton.press();
  361. event.accepted = true;
  362. }
  363. }
  364. }
  365. Keys.onReleased: {
  366. if (!viewLoader.focus) {
  367. if (event.key == Qt.Key_Context1) {
  368. optionsButton.release();
  369. optionsButton.click();
  370. event.accepted = true;
  371. }
  372. if (event.key == Qt.Key_Context2) {
  373. exitButton.release();
  374. exitButton.click();
  375. event.accepted = true;
  376. }
  377. }
  378. }
  379. Text {
  380. id: exitButton
  381. function click() {
  382. Qt.quit();
  383. }
  384. function press() {
  385. scale = 0.9
  386. color = "lightgray"
  387. }
  388. function release() {
  389. scale = 1
  390. color = "#ffffff"
  391. }
  392. text: "Exit"
  393. font.pixelSize: main.largeFontPixelSize
  394. color: focus ? "black" : "#ffffff"
  395. anchors {
  396. right: parent.right
  397. rightMargin: 5
  398. bottom: parent.bottom
  399. bottomMargin: 5
  400. }
  401. MouseArea {
  402. id: exitMouseArea
  403. anchors.fill: parent
  404. onPressed: parent.press();
  405. onReleased: parent.release();
  406. onClicked: parent.click();
  407. }
  408. }
  409. Loader {
  410. id: viewLoader
  411. property string file
  412. property int initX: parent.width / 2
  413. property int initY: parent.height / 2
  414. function switchTo(fileName, fromX, fromY)
  415. {
  416. if (fileName != file) {
  417. file = fileName;
  418. initX = fromX;
  419. initY = fromY;
  420. if (item)
  421. item.state = "";
  422. else
  423. source = file;
  424. focus = true;
  425. }
  426. }
  427. function close(fromX, fromY)
  428. {
  429. if (fromX != undefined && fromY != undefined) {
  430. initX = fromX;
  431. initY = fromY;
  432. }
  433. switchTo("", initX, initY);
  434. focus = false;
  435. mainBoard.focus = true;
  436. }
  437. anchors.centerIn: parent
  438. focus: true
  439. source: "Menu.qml"
  440. onLoaded: item.state = "open"
  441. }
  442. } // AppWindow