Warning, /education/khangman/src/qml/GamePage.qml is written in an unsupported language. File is not indexed.
0001 // SPDX-FileCopyrightText: 2012 Laszlo Papp <lpapp@kde.org> 0002 // SPDX-FileCopyrightText: 2014 Rahul Chowdhury <rahul.chowdhury@kdemail.net> 0003 // SPDX-License-Identifier: LGPL-2.1-or-later 0004 0005 import QtQuick 0006 import QtQuick.Controls 0007 import QtQuick.Layouts 0008 import QtQuick.Window 0009 import QtMultimedia 0010 import QtQml 0011 import Qt5Compat.GraphicalEffects 0012 0013 import org.kde.kirigami as Kirigami 0014 import org.kde.kirigamiaddons.formcard as FormCard 0015 import org.kde.kirigamiaddons.delegates as Delegates 0016 import org.kde.newstuff as NewStuff 0017 import org.kde.khangman 0018 0019 Kirigami.Page { 0020 id: gamePage 0021 0022 focus: true 0023 0024 property variant alphabet: KHangMan.alphabet 0025 property color currentWordLetterRectangleColor: Qt.rgba(0, 0, 0, 0) 0026 property int countDownTimerValue: KHangMan.resolveTime 0027 property int gallowsSeriesCounter: 0 0028 property bool initialized: false 0029 property alias isPlaying: secondTimer.running 0030 property string missedLetters: "" 0031 0032 background: Image { 0033 id: backgroundImage 0034 smooth: true 0035 anchors.fill: parent 0036 source: KHangMan.backgroundUrl 0037 } 0038 0039 function nextWord(): void { 0040 KHangMan.nextWord(); 0041 0042 countDownTimerValue = KHangMan.resolveTime; 0043 0044 // Re enable all alphabet buttons 0045 for (var i = 0; i < alphabetLetterRepeater.count; ++i) { 0046 alphabetLetterRepeater.itemAt(i).enabled = true; 0047 alphabetLetterRepeater.itemAt(i).buttonColor = "black"; 0048 } 0049 0050 // Reset variables for the new word. 0051 gallowsSeriesCounter = 0; 0052 successImage.visible = false; 0053 missedLetters = ""; 0054 0055 hintLabel.visible = false; 0056 0057 if (KHangMan.soundEnabled) { 0058 nextWordSoundEffect.play(); 0059 } 0060 } 0061 0062 function startTimer(): void { 0063 secondTimer.repeat = true; 0064 secondTimer.running = true; 0065 secondTimer.start(); 0066 } 0067 0068 function disableLetterButton(letter: string): void { 0069 for (var i = 0; i < alphabetLetterRepeater.count; ++i) { 0070 if (alphabetLetterRepeater.itemAt(i).upperCase == letter) { 0071 alphabetLetterRepeater.itemAt(i).enabled = false; 0072 break; 0073 } 0074 } 0075 } 0076 0077 function guessLetter(letter: string): void { 0078 letter = letter.toUpperCase() 0079 if (KHangMan.soundEnabled) { 0080 khangmanAlphabetButtonPressSoundEffect.play(); 0081 } 0082 0083 disableLetterButton(letter); 0084 changeButtonColor(letter); 0085 if (KHangMan.containsChar(letter)) { 0086 KHangMan.replaceLetters(letter); 0087 0088 if (KHangMan.isResolved()) { 0089 // the current puzzle is solved 0090 KHangMan.winCount++; 0091 successImage.visible = true; 0092 khangmanResultTimer.start(); 0093 0094 if (KHangMan.soundEnabled) { 0095 ewDialogAppearSoundEffect.play(); 0096 } 0097 } 0098 } else { 0099 // Only add to missedLetters if it's not already there 0100 if (missedLetters.indexOf(letter) == -1) { 0101 if (gallowsSeriesCounter++ == 9) { 0102 // wrong solution given for current puzzle 0103 KHangMan.lossCount++; 0104 if (KHangMan.soundEnabled) { 0105 wrongSoundEffect.play(); 0106 } 0107 0108 khangmanResultTimer.start(); 0109 } 0110 0111 missedLetters += letter 0112 } 0113 } 0114 } 0115 0116 function changeButtonColor(letter: string): void { 0117 for (var i = 0; i < alphabetLetterRepeater.count; ++i) { 0118 if (alphabetLetterRepeater.itemAt(i).upperCase == letter) { 0119 alphabetLetterRepeater.itemAt(i).buttonColor = KHangMan.containsChar(letter) ? "green" : "red"; 0120 } 0121 } 0122 } 0123 0124 SelectionDialog { 0125 id: categorySelectionDialog; 0126 0127 title: i18n("Choose the word category"); 0128 model: KHangMan.categories 0129 Component.onCompleted: { 0130 currentIndex = KHangMan.currentCategory; 0131 } 0132 0133 onCurrentIndexChanged: { 0134 if (KHangMan.soundEnabled) { 0135 if (!initialized) { 0136 initialized = true; 0137 } else { 0138 nextWordSoundEffect.play(); 0139 } 0140 } 0141 0142 KHangMan.setCurrentCategory(currentIndex); 0143 KHangMan.readFile(); 0144 nextWord(); 0145 } 0146 0147 delegate: Delegates.RoundedItemDelegate { 0148 required property int index 0149 required property string modelData 0150 0151 text: modelData 0152 onClicked: { 0153 categorySelectionDialog.currentIndex = index 0154 categorySelectionDialog.close(); 0155 } 0156 } 0157 } 0158 0159 SelectionDialog { 0160 id: languageSelectionDialog; 0161 0162 title: i18n("Select a language"); 0163 model: KHangMan.languages 0164 Component.onCompleted: currentIndex = KHangMan.currentLanguage 0165 0166 delegate: Delegates.RoundedItemDelegate { 0167 required property int index 0168 required property string modelData 0169 0170 text: modelData 0171 0172 onClicked: { 0173 languageSelectionDialog.currentIndex = index; 0174 0175 KHangMan.setCurrentLanguage(index); 0176 KHangMan.readFile(); 0177 nextWord(); 0178 languageSelectionDialog.close(); 0179 } 0180 } 0181 } 0182 0183 SelectionDialog { 0184 id: themeSelectionDialog; 0185 title: i18n("Select a theme"); 0186 model: KHangMan.themes 0187 Component.onCompleted: currentIndex = KHangMan.currentTheme 0188 0189 delegate: Delegates.RoundedItemDelegate { 0190 required property int index 0191 required property string modelData 0192 0193 text: modelData 0194 0195 onClicked: { 0196 themeSelectionDialog.currentIndex = index; 0197 0198 KHangMan.setCurrentTheme(index); 0199 themeSelectionDialog.close(); 0200 } 0201 } 0202 } 0203 0204 Timer { 0205 id: secondTimer; 0206 interval: 1000; 0207 repeat: true; 0208 running: false; 0209 triggeredOnStart: false; 0210 0211 onTriggered: { 0212 if (KHangMan.resolveTime != 0 && --countDownTimerValue == 0) { 0213 stop(); 0214 khangmanResultTimer.start(); 0215 if (KHangMan.soundEnabled) { 0216 wrongSoundEffect.play(); 0217 } 0218 } 0219 } 0220 } 0221 0222 Timer { 0223 id: khangmanResultTimer; 0224 interval: 1000; 0225 repeat: false; 0226 running: false; 0227 triggeredOnStart: false; 0228 0229 onTriggered: { 0230 nextWord(); 0231 startTimer(); 0232 } 0233 } 0234 0235 actions: [ 0236 Kirigami.Action { 0237 id: playPauseButton 0238 icon.name: gamePage.isPlaying ? "media-playback-pause" : "media-playback-start" 0239 0240 text: gamePage.isPlaying ? i18n("Pause") : i18n("Play") 0241 0242 onTriggered: { 0243 if (gamePage.isPlaying ) { // game is currently going on, so pause it 0244 secondTimer.repeat = false 0245 secondTimer.running = false 0246 hintLabel.visible = false 0247 secondTimer.stop(); 0248 } else { // the game is paused or not yet started, so resume or start it 0249 // if the game is not yet started, play nextWordSoundeffect 0250 // denotes the game is not yet started, should return false if game is paused instead 0251 if (KHangMan.soundEnabled) { 0252 nextWordSoundEffect.play() 0253 } 0254 startTimer() 0255 } 0256 } 0257 }, 0258 0259 Kirigami.Action { 0260 id: themeSelectionButton 0261 text: themeSelectionDialog.model[themeSelectionDialog.currentIndex] 0262 0263 onTriggered: { 0264 themeSelectionDialog.open() 0265 } 0266 }, 0267 0268 Kirigami.Action { 0269 id: settingsButton 0270 icon.name: "settings-configure-symbolic" 0271 text: i18nc("@action:button", "Configure") 0272 0273 property bool wasPlaying: false 0274 0275 onTriggered: { 0276 // if game is currently going on then pause it 0277 settingsButton.wasPlaying = isPlaying 0278 if( gamePage.isPlaying ) { 0279 secondTimer.repeat = false 0280 secondTimer.running = false 0281 hintLabel.visible = false 0282 secondTimer.stop(); 0283 } 0284 0285 const item = applicationWindow().pageStack.pushDialogLayer(Qt.createComponent("org.kde.khangman", "SettingsPage"), {}, {title: i18n("Configure"), width: Kirigami.Units.gridUnit * 24}); 0286 0287 item.okClicked.connect(() => { 0288 // close the settings dialog 0289 if (wasPlaying) { 0290 // game is going on, so load a new word and start with the saved settings 0291 nextWord() 0292 startTimer() 0293 } 0294 }); 0295 0296 item.cancelClicked.connect(() => { 0297 if (wasPlaying) { 0298 // game was in progress, so resume the timer countdown 0299 startTimer() 0300 } 0301 }); 0302 } 0303 }, 0304 0305 NewStuff.Action { 0306 id: ghnsButton 0307 0308 configFile: "khangman.knsrc" 0309 icon.name: "get-hot-new-stuff" 0310 text: i18n("Get new language files") 0311 visible: NewStuff.Settings.allowedByKiosk 0312 0313 onEntryEvent: (entry, event) => { 0314 if (event === NewStuff.Entry.StatusChangedEvent) { 0315 KHangMan.slotDownloadNewStuff(entry) 0316 } 0317 } 0318 }, 0319 0320 Kirigami.Action { 0321 id: showHandbookButton 0322 icon.name: "help-browser" 0323 text: i18n("View the KHangMan Handbook") 0324 displayHint: Kirigami.DisplayHint.AlwaysHide 0325 0326 onTriggered: { 0327 KHangMan.showHandbook() 0328 } 0329 }, 0330 0331 Kirigami.Action { 0332 id: aboutKhangmanButton 0333 icon.name: "khangman" 0334 text: i18n("About KHangMan") 0335 displayHint: Kirigami.DisplayHint.AlwaysHide 0336 0337 onTriggered: { 0338 applicationWindow().pageStack.pushDialogLayer("qrc:/qt/qml/org/kde/khangman/qml/Settings/AboutPage.qml", {} , { 0339 width: Kirigami.Units.gridUnit * 24, 0340 title: i18n("About KHangMan") 0341 }) 0342 } 0343 }, 0344 0345 Kirigami.Action { 0346 id: aboutKDEButton 0347 text: i18n("About KDE") 0348 icon.name: "help-about-symbolic" 0349 displayHint: Kirigami.DisplayHint.AlwaysHide 0350 0351 onTriggered: { 0352 applicationWindow().pageStack.pushDialogLayer("qrc:/qt/qml/org/kde/khangman/qml/Settings/AboutKDEPage.qml", {}, { 0353 width: Kirigami.Units.gridUnit * 24, 0354 title: i18n("About KDE") 0355 }) 0356 } 0357 } 0358 ] 0359 0360 // display the remaining number of wrong guesses 0361 Row { 0362 id: misses 0363 spacing: 5 0364 visible: isPlaying 0365 0366 anchors { 0367 top: parent.top 0368 topMargin: 5 0369 right: parent.right 0370 rightMargin: 5 0371 } 0372 0373 Label { 0374 id: missesLabel 0375 text: i18n("Remaining guesses: ") 0376 font.pixelSize: 40 0377 font.bold: true 0378 color: KHangMan.letterColor 0379 } 0380 0381 Text { 0382 id: remainingGuessesCount 0383 text: i18n(10 - gallowsSeriesCounter) 0384 color: gallowsSeriesCounter >= 7 ? "red" : "black" 0385 font.pixelSize: 40 0386 font.bold: true 0387 } 0388 } 0389 0390 Label { 0391 id: scoreLabel 0392 visible: isPlaying 0393 0394 anchors { 0395 top: misses.top 0396 left: parent.left 0397 leftMargin: 5 0398 } 0399 0400 text: i18n("Score: ") 0401 font.pixelSize: 40 0402 font.bold: true 0403 color: KHangMan.letterColor 0404 } 0405 0406 Label { 0407 id: netScoreLabel 0408 visible: isPlaying 0409 0410 anchors { 0411 left: scoreLabel.right 0412 top: scoreLabel.top 0413 } 0414 0415 text: KHangMan.netScore 0416 color: KHangMan.netScore < 0 ? "red" : "black" 0417 font.pixelSize: 40 0418 font.bold: true 0419 } 0420 0421 Row { 0422 id: winCountRow 0423 spacing: 15 0424 visible: isPlaying 0425 0426 anchors { 0427 top: scoreLabel.bottom 0428 left: parent.left 0429 leftMargin: 5 0430 } 0431 0432 Label { 0433 id: winLabel 0434 text: i18n("Wins: ") 0435 font.pixelSize: 40 0436 font.bold: true 0437 color: KHangMan.letterColor 0438 } 0439 0440 Label { 0441 id: winCountLabel 0442 text: KHangMan.winCount 0443 font.pixelSize: 40 0444 font.bold: true 0445 color: KHangMan.letterColor 0446 } 0447 } 0448 0449 Row { 0450 id: lossCountRow 0451 spacing: 15 0452 visible: isPlaying 0453 0454 anchors { 0455 top: winCountRow.bottom 0456 left: parent.left 0457 leftMargin: 5 0458 } 0459 0460 Label { 0461 id: lossLabel 0462 text: i18n("Losses: ") 0463 font.pixelSize: 40 0464 font.bold: true 0465 color: KHangMan.letterColor 0466 } 0467 0468 Label { 0469 id: lossCountLabel 0470 text: KHangMan.lossCount 0471 font.pixelSize: 40 0472 font.bold: true 0473 color: KHangMan.letterColor 0474 } 0475 } 0476 0477 Kirigami.Icon { 0478 id: successImage 0479 0480 source: "data-success" 0481 visible: false 0482 0483 width: Kirigami.Units.iconSizes.huge 0484 height: Kirigami.Units.iconSizes.huge 0485 0486 anchors { 0487 horizontalCenter: parent.horizontalCenter; 0488 verticalCenter: parent.verticalCenter; 0489 verticalCenterOffset: -parent.height/4; 0490 } 0491 } 0492 0493 Image { 0494 id: gallowsSeriesImage; 0495 source: gallowsSeriesCounter == 0 ? "" : "qrc:/qml/gallows/gallows" + gallowsSeriesCounter + ".png" 0496 visible: (isPlaying && gallowsSeriesCounter > 0) 0497 0498 anchors { 0499 horizontalCenter: parent.horizontalCenter; 0500 verticalCenter: parent.verticalCenter; 0501 verticalCenterOffset: -parent.height/4; 0502 } 0503 } 0504 0505 Grid { 0506 id: currentWordGrid; 0507 visible: gamePage.isPlaying 0508 anchors { 0509 centerIn: parent; 0510 } 0511 0512 spacing: 5; 0513 columns: 13; 0514 Repeater { 0515 id: currentWordLetterRepeater; 0516 model: KHangMan.currentWord; 0517 LetterElement { 0518 id: currentWordLetterId; 0519 letterText: modelData; 0520 } 0521 } 0522 } 0523 0524 Grid { 0525 id: alphabetGrid; 0526 visible: gamePage.isPlaying 0527 anchors { 0528 horizontalCenter: parent.horizontalCenter; 0529 bottom: parent.bottom; 0530 bottomMargin: 10; 0531 } 0532 0533 spacing: gamePage.width/35; 0534 columns: 13; 0535 Repeater { 0536 id: alphabetLetterRepeater; 0537 model: alphabet; 0538 Button { 0539 id: alphabetButton; 0540 property string letter: modelData 0541 property string upperCase: modelData.toUpperCase() 0542 property string buttonColor: "black" 0543 0544 background: Rectangle { 0545 id: alphabetLetterIdStyleRectangle 0546 implicitWidth: gamePage.width / 22 0547 implicitHeight: gamePage.width / 22 0548 color: buttonColor 0549 radius: 8 0550 layer.enabled: true 0551 layer.effect: DropShadow { 0552 radius: 4 0553 horizontalOffset: 3 0554 verticalOffset: 3 0555 spread: 0 0556 samples: radius * 2 0557 source: alphabetLetterIdStyleRectangle 0558 color: Qt.rgba(0, 0, 0, 0.5) 0559 transparentBorder: true 0560 } 0561 } 0562 0563 contentItem: Text { 0564 id: buttonLabel 0565 anchors.centerIn: parent 0566 text: letter 0567 font.family : "Arial" 0568 font.pixelSize: gamePage.width / 40 0569 font.capitalization : Font.AllUppercase 0570 font.weight : Font.Bold 0571 horizontalAlignment : Text.AlignHCenter 0572 verticalAlignment : Text.AlignVCenter 0573 color: parent.enabled ? "white" : "grey" 0574 } 0575 0576 onClicked: { 0577 guessLetter(modelData); 0578 } 0579 } 0580 } 0581 } 0582 0583 Label { 0584 id: hintLabel 0585 text: KHangMan.currentHint 0586 font.family: "serif-sans" 0587 color: "green" 0588 font.italic: true 0589 font.pixelSize: gamePage.width / 60 0590 anchors.top: currentWordGrid.bottom 0591 anchors.bottom: alphabetGrid.top 0592 anchors.horizontalCenter: parent.horizontalCenter 0593 visible: false 0594 } 0595 0596 footer: ToolBar { 0597 id: mainPageTools 0598 visible: isPlaying 0599 0600 RowLayout { 0601 anchors.fill: parent 0602 0603 ToolButton { 0604 id: helpHintButton 0605 icon.source: "Images/help-hint.png" 0606 ToolTip.text: i18n("Display the hint.") 0607 ToolTip.visible: hovered 0608 ToolTip.delay: Kirigami.Units.toolTipDelay 0609 enabled: hintLabel.text != "" 0610 0611 onClicked: { 0612 // make the button toggle between display and hide the hint 0613 hintLabel.visible = hintLabel.visible ? false : true 0614 } 0615 } 0616 0617 ToolButton { 0618 id: categorySelectionButton 0619 Layout.fillWidth: true 0620 text: categorySelectionDialog.model[categorySelectionDialog.currentIndex]; 0621 ToolTip.text: i18n("Change the category.") 0622 ToolTip.visible: hovered 0623 ToolTip.delay: Kirigami.Units.toolTipDelay 0624 0625 onClicked: { 0626 categorySelectionDialog.open(); 0627 } 0628 } 0629 0630 ToolButton { 0631 id: languageSelectionButton 0632 Layout.fillWidth: true 0633 text: languageSelectionDialog.model[languageSelectionDialog.currentIndex] 0634 ToolTip.text: i18n("Change the language.") 0635 ToolTip.visible: hovered 0636 ToolTip.delay: Kirigami.Units.toolTipDelay 0637 0638 onClicked: { 0639 languageSelectionDialog.open() 0640 } 0641 } 0642 0643 ToolButton { 0644 id: revealWordButton 0645 Layout.fillWidth: true 0646 text: i18n("Reveal Word") 0647 ToolTip.text: i18n("Reveal the current word.") 0648 ToolTip.visible: hovered 0649 ToolTip.delay: Kirigami.Units.toolTipDelay 0650 0651 onClicked: { 0652 KHangMan.revealCurrentWord(); 0653 KHangMan.lossCount++; 0654 if (KHangMan.soundEnabled) { 0655 wrongSoundEffect.play(); 0656 } 0657 0658 khangmanResultTimer.start(); 0659 } 0660 } 0661 0662 Text { 0663 id: timerText 0664 visible: KHangMan.resolveTime == 0 ? false : true 0665 text: Math.floor(countDownTimerValue / 60) + ":" + Math.floor(countDownTimerValue % 60 / 10) 0666 + Math.floor(countDownTimerValue % 60 % 10) 0667 } 0668 0669 ToolButton { 0670 id: nextWordButton 0671 Layout.fillWidth: true 0672 icon.name: "go-next" 0673 ToolTip.text: i18n("Load the next word and start a new game.") 0674 ToolTip.visible: hovered 0675 ToolTip.delay: Kirigami.Units.toolTipDelay 0676 0677 onClicked: { 0678 if (KHangMan.soundEnabled) { 0679 nextWordSoundEffect.play(); 0680 } 0681 0682 nextWord(); 0683 0684 secondTimer.repeat = true; 0685 secondTimer.restart(); 0686 } 0687 } 0688 } 0689 } 0690 0691 Keys.onPressed: (event) => { 0692 if (event.text.length > 0) { 0693 guessLetter(event.text); 0694 } 0695 } 0696 }