diff --git a/src/qml/common/IconToolButton.qml b/src/qml/common/IconToolButton.qml index 7f68410..d54d6f5 100644 --- a/src/qml/common/IconToolButton.qml +++ b/src/qml/common/IconToolButton.qml @@ -1,68 +1,68 @@ /* * Copyright 2017 Sebastian Gottfried * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.9 import QtQuick.Controls 2.2 import ktouch 1.0 ToolButton { id: button - KColorScheme { + property alias color: content.color + property alias iconName: content.iconName + property color backgroundColor: button.colorScheme.normalBackground + + property KColorScheme colorScheme: KColorScheme { id: buttonColorScheme colorGroup: button.enabled? KColorScheme.Active: KColorScheme.Disabled colorSet: KColorScheme.Button } - property alias color: content.color - property alias iconName: content.iconName - property color backgroundColor: button.colorScheme.normalBackground - property alias colorScheme: buttonColorScheme padding: 0 hoverEnabled: true contentItem: IconLabel { id: content text: button.text color: button.colorScheme.normalText elide: "ElideNone" } background: Item { Rectangle { anchors.fill: parent opacity: (button.checked? 0.6: 0) + (button.activeFocus || button.hovered? 0.3: 0) color: button.backgroundColor Behavior on opacity { NumberAnimation { duration: 150 } } } FocusBar { anchors { left: parent.left right: parent.right bottom: parent.bottom } height: 3 control: button } } } diff --git a/src/qml/common/MessageBox.qml b/src/qml/common/MessageBox.qml index 9a2b9f7..39af6c2 100644 --- a/src/qml/common/MessageBox.qml +++ b/src/qml/common/MessageBox.qml @@ -1,124 +1,111 @@ /* - * Copyright 2012 Sebastian Gottfried - * Copyright 2015 Sebastian Gottfried + * Copyright 2018 Sebastian Gottfried * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.9 -import QtQuick.Controls 1.3 -import org.kde.kquickcontrolsaddons 2.0 + +import "../common" Rectangle { id: item anchors.verticalCenter: parent.verticalCenter radius: 3 color: "#eee4be" - height: layout.height + 6 - width: layout.width + 6 + height: label.height + 6 + width: label.width + 6 smooth: true function showMessage(msg, iconSource) { item.state = "hidden"; label.text = msg - icon.icon = iconSource || "" + label.iconName = iconSource || "" item.state = "normal" } function clearMessage() { item.state = "cleared" } function clearMessageImmediately() { item.state = "hidden" } border { width: 1 color: "#decd87" } transform: Scale { id: itemScaler origin.x: 0 origin.y: 0 } state: "hidden" - Row { - id: layout + IconLabel { anchors.centerIn: parent - width: icon.width + spacing + label.width - spacing: icon.valid? 3: 0 - - QIconItem { - id: icon - width: height - height: icon? label.height: 0 - } - - Label { - id: label - color: "#000000" - } + id: label + padding: 2 } states: [ State { name: "normal" PropertyChanges { target: itemScaler xScale: 1 } }, State { name: "hidden" PropertyChanges { target: itemScaler xScale: 0 } }, State { name: "cleared" PropertyChanges { target: itemScaler xScale: 0 } } ] transitions: [ Transition { from: "*" to: "normal" NumberAnimation { target: itemScaler property: "xScale" duration: 500 easing.type: Easing.InOutQuad } }, Transition { from: "normal" to: "cleared" NumberAnimation { target: itemScaler property: "xScale" duration: 500 easing.type: Easing.InOutQuad } } ] } diff --git a/src/qml/qml.qrc b/src/qml/qml.qrc index 864b688..d8e4292 100644 --- a/src/qml/qml.qrc +++ b/src/qml/qml.qrc @@ -1,67 +1,67 @@ common/AutoTriggerButton.qml common/Balloon.qml common/Collapsable.qml common/ComboBox.qml common/FocusBar.qml common/GridView.qml common/Icon.qml common/IconButton.qml common/IconLabel.qml common/IconToolButton.qml common/InfoItem.qml common/InformationTable.qml common/InlineToolbar.qml common/Label.qml common/LearningProgressChart.qml common/ListItem.qml common/ListView.qml common/MessageBox.qml common/MonochromeIcon.qml common/PopupDialog.qml common/RadioButton.qml common/ScrollBar.qml common/ScrollView.qml common/SelectionGrip.qml common/SelectionRectangle.qml common/TextArea.qml common/TextField.qml common/ToolBar.qml common/ToolSeparator.qml common/ToolTip.qml homescreen/CourseDescriptionItem.qml homescreen/CourseSelector.qml homescreen/CourseSelectorKeyboardLayoutItem.qml homescreen/CourseSelectorKeyboardLayoutList.qml homescreen/HomeScreen.qml homescreen/InitialProfileDialog.qml homescreen/KeyboardLayoutMismatchMessage.qml homescreen/LessonDeletedMessage.qml homescreen/LessonEditorDialog.qml homescreen/LessonLockedNotice.qml homescreen/LessonSelector.qml homescreen/LessonSelectorItem.qml homescreen/ProfileComboBox.qml homescreen/ProfileDetailsItem.qml homescreen/ProfileForm.qml homescreen/ProfileSelector.qml homescreen/StatPopupDialog.qml keyboard/KeyItem.qml keyboard/KeyLabel.qml keyboard/Keyboard.qml keyboard/KeyboardLayoutEditor.qml main.qml meters/AccuracyMeter.qml meters/CharactersPerMinuteMeter.qml meters/ElapsedTimeMeter.qml meters/Meter.qml meters/StatBox.qml scorescreen/ScoreScreen.qml trainingscreen/KeyboardUnavailableNotice.qml trainingscreen/TrainingScreen.qml - trainingscreen/TrainingScreenMenuOverlay.qml + trainingscreen/TrainingScreenMenu.qml trainingscreen/TrainingScreenToolbar.qml trainingscreen/TrainingWidget.qml diff --git a/src/qml/trainingscreen/KeyboardUnavailableNotice.qml b/src/qml/trainingscreen/KeyboardUnavailableNotice.qml index 8ec9c1f..9dfab5a 100644 --- a/src/qml/trainingscreen/KeyboardUnavailableNotice.qml +++ b/src/qml/trainingscreen/KeyboardUnavailableNotice.qml @@ -1,53 +1,38 @@ /* - * Copyright 2012 Sebastian Gottfried - * Copyright 2015 Sebastian Gottfried + * Copyright 2018 Sebastian Gottfried * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.9 -import QtQuick.Controls 1.3 -import QtQuick.Layouts 1.3 -import org.kde.kquickcontrolsaddons 2.0 import ktouch 1.0 +import '../common' + Item { id: root - height: row.height + 20 + property KColorScheme colorScheme: KColorScheme {} + + height: label.height + 20 - Row { - id: row + IconLabel { + id: label anchors.centerIn: parent width: parent.width - 60 - height: Math.max(icon.height, label.height) - spacing: 3 - - QIconItem { - id: icon - anchors.verticalCenter: parent.verticalCenter - width: 22 - height: 22 - icon: "dialog-warning" - } - - Label { - id: label - anchors.verticalCenter: parent.verticalCenter - width: parent.width - icon.width - parent.spacing - text: i18n("No visualization available for your keyboard layout.") - color: "white" - } + iconName: "dialog-warning" + text: i18n("No visualization available for your keyboard layout.") + color: colorScheme.normalText } } diff --git a/src/qml/trainingscreen/TrainingScreen.qml b/src/qml/trainingscreen/TrainingScreen.qml index f05f527..5da2b6d 100644 --- a/src/qml/trainingscreen/TrainingScreen.qml +++ b/src/qml/trainingscreen/TrainingScreen.qml @@ -1,331 +1,333 @@ /* - * Copyright 2013 Sebastian Gottfried - * Copyright 2015 Sebastian Gottfried + * Copyright 2018 Sebastian Gottfried * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.9 -import QtQuick.Controls 1.3 import QtQuick.Layouts 1.3 import ktouch 1.0 +import "../common" import "../keyboard" import "../meters" FocusScope { id: screen property KeyboardLayout keyboardLayout property Profile profile property Course course property Lesson lesson property alias stats: stats property alias referenceStats: referenceStats signal restartRequested() signal abortRequested() signal finished() property bool trainingStarted: false property bool trainingFinished: true property bool isActive: Qt.application.active function setLessonKeys() { if (!lesson) return; var chars = lesson.characters; var keyItems = keyboard.keyItems() var modifierItems = [] var usedModifiers = {} for (var i = 0; i < keyItems.length; i++) { var key = keyItems[i].key if (key.keyType() == "key") { keyItems[i].enabled = false; for (var j = 0; j < key.keyCharCount; j++) { var keyChar = key.keyChar(j) if (chars.indexOf(keyChar.value) != -1) { keyItems[i].enabled = true; if (keyChar.modifier !== "") { usedModifiers[keyChar.modifier] = true } } } } else { var type = keyItems[i].key.type if (type != SpecialKey.Return && type != SpecialKey.Backspace && type != SpecialKey.Space) { modifierItems.push(keyItems[i]) keyItems[i].enabled = false } else if (type == SpecialKey.Return && preferences.nextLineWithSpace) { keyItems[i].enabled = false } } } for (i = 0; i < modifierItems.length; i++) { var modifierItem = modifierItems[i] modifierItem.enabled = !!usedModifiers[modifierItem.key.modifierId] } } function reset() { toolbar.reset() trainingWidget.reset() screen.trainingStarted = false screen.trainingFinished = true profileDataAccess.loadReferenceTrainingStats(referenceStats, screen.profile, screen.course.id, screen.lesson.id) profileDataAccess.saveCourseProgress(lesson.id, profile, course.id, ProfileDataAccess.LastSelectedLesson) } function start() { screen.trainingFinished = false screen.trainingStarted = true } function forceActiveFocus() { trainingWidget.forceActiveFocus() } onLessonChanged: setLessonKeys() onIsActiveChanged: { if (!screen.isActive) { stats.stopTraining() } } + KColorScheme { + id: colorScheme + colorGroup: KColorScheme.Active + colorSet: KColorScheme.Complementary + } + TrainingStats { id: stats onTimeIsRunningChanged: { if (timeIsRunning) { screen.trainingStarted = false } } } TrainingStats { id: referenceStats } Shortcut { sequence: "Escape" enabled: screen.visible onActivated: { - if (menuOverlay.active) { - menuOverlay.hide() - } - else { - menuOverlay.show() + if (!menu.visible) { + menu.open() } } - } ColumnLayout { id: screenContent anchors.fill: parent spacing: 0 BorderImage { Layout.fillWidth: true Layout.preferredHeight: 41 border { top: 1 bottom: 1 } cache: false source: utils.findImage("trainingscreen-toolbar.png") horizontalTileMode: BorderImage.Repeat verticalTileMode: BorderImage.Repeat TrainingScreenToolbar { id: toolbar anchors.fill: parent trainingStarted: screen.trainingStarted trainingFinished: screen.trainingFinished stats: stats - menuOverlayItem: menuOverlay + menu: menu } } BorderImage { id: header Layout.fillWidth: true Layout.preferredHeight: visible? 130: 0 visible: preferences.showStatistics border { top: 1 bottom: 1 } source: utils.findImage("trainingscreen-header.png") cache: false StatBox { anchors.centerIn: parent width: parent.width - 60 stats: stats referenceStats: referenceStats } } BorderImage { id: body Layout.fillWidth: true Layout.fillHeight: true border { top: 1 bottom: 1 } source: utils.findImage("trainingscreen-viewport.png") cache: false TrainingWidget { id: trainingWidget anchors.fill: parent lesson: screen.lesson keyboardLayout: screen.keyboardLayout trainingStats: stats overlayContainer: trainingOverlayContainer onKeyPressed: keyboard.handleKeyPress(event) onKeyReleased: keyboard.handleKeyRelease(event) onNextCharChanged: keyboard.updateKeyHighlighting() onIsCorrectChanged: keyboard.updateKeyHighlighting() onFinished: { profileDataAccess.saveTrainingStats(stats, screen.profile, screen.course.id, screen.lesson.id) screen.finished(stats) screen.trainingFinished = true } } BorderImage { anchors.fill: parent border { top: 3 bottom: 3 } source: utils.findImage("trainingscreen-viewport-shadow.png") cache: false } } BorderImage { id: footer visible: preferences.showKeyboard Layout.fillWidth: true Layout.preferredHeight: visible? screen.keyboardLayout.isValid? Math.round(Math.min((parent.height - toolbar.height - header.height) / 2, parent.width / keyboard.aspectRatio)): keyboardUnavailableNotice.height: 0 border { top: 1 bottom: 1 } source: utils.findImage("trainingscreen-footer.png") cache: false + Keyboard { id: keyboard property variant highlightedKeys: [] function highlightKey(which) { for (var i = 0; i < highlightedKeys.length; i++) highlightedKeys[i].isHighlighted = false var keys = findKeyItems(which) var newHighlightedKeys = [] for (var index = 0; index < keys.length ; index++) { var key = keys[index] if (key) { key.isHighlighted = true newHighlightedKeys.push(key) if (typeof which == "string") { for (var i = 0; i < key.key.keyCharCount; i++) { var keyChar = key.key.keyChar(i) if (keyChar.value == which && keyChar.modifier != "") { var modifier = findModifierKeyItem(keyChar.modifier) if (modifier) { modifier.isHighlighted = true newHighlightedKeys.push(modifier) } break } } } } } highlightedKeys = newHighlightedKeys } function updateKeyHighlighting() { if (!visible) return; if (trainingWidget.isCorrect) { if (trainingWidget.nextChar !== "") { highlightKey(trainingWidget.nextChar) } else { highlightKey(preferences.nextLineWithSpace? Qt.Key_Space: Qt.Key_Return) } } else { highlightKey(Qt.Key_Backspace) } } keyboardLayout: screen.keyboardLayout anchors { fill: parent leftMargin: 30 rightMargin: 30 topMargin: 10 bottomMargin: 10 } onKeyboardUpdate: { setLessonKeys() highlightedKeys = [] updateKeyHighlighting() } } KeyboardUnavailableNotice { id: keyboardUnavailableNotice + colorScheme: colorScheme visible: !screen.keyboardLayout.isValid + width: parent.width } } } Item { id: trainingOverlayContainer anchors.fill: parent } - TrainingScreenMenuOverlay { - id: menuOverlay - blurSource: screenContent - anchors.fill: parent + TrainingScreenMenu { + id: menu onClosed: trainingWidget.forceActiveFocus() onRestartRequested: screen.restartRequested() onAbortRequested: screen.abortRequested() } } diff --git a/src/qml/trainingscreen/TrainingScreenMenu.qml b/src/qml/trainingscreen/TrainingScreenMenu.qml new file mode 100644 index 0000000..5f483b2 --- /dev/null +++ b/src/qml/trainingscreen/TrainingScreenMenu.qml @@ -0,0 +1,93 @@ +/* + * Copyright 2018 Sebastian Gottfried + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +import QtQuick 2.9 +import QtQuick.Layouts 1.3 +import ktouch 1.0 + +import '../common' + + +PopupDialog { + id: root + + signal restartRequested() + signal abortRequested() + + onOpened: { + resumeButton.forceActiveFocus() + } + + title: i18n("Menu") + + padding: 20 + + contentItem: Item { + width: column.width + height: column.height + + Column { + id: column + focus: true + anchors.centerIn: parent + spacing: 20 + width: 1.5 * Math.max(resumeButton.implicitWidth, restartButton.implicitWidth, returnButton.implicitWidth) + + IconButton { + id: resumeButton + iconName: "go-next-view" + text: i18n("Resume Training") + bgColor: colorScheme.positiveBackground + width: parent.width + onClicked: close() + KeyNavigation.backtab: returnButton + KeyNavigation.tab: restartButton + KeyNavigation.down: restartButton + } + + IconButton { + id: restartButton + iconName: "view-refresh" + text: i18n("Restart Lesson") + width: parent.width + onClicked: { + close() + restartRequested() + } + KeyNavigation.backtab: resumeButton + KeyNavigation.tab: returnButton + KeyNavigation.up: resumeButton + KeyNavigation.down: returnButton + } + + IconButton { + id: returnButton + iconName: "go-home" + text: i18n("Return to Home Screen") + width: parent.width + onClicked: { + close() + abortRequested() + } + KeyNavigation.backtab: restartButton + KeyNavigation.tab: resumeButton + KeyNavigation.up: restartButton + } + } + } +} + diff --git a/src/qml/trainingscreen/TrainingScreenMenuOverlay.qml b/src/qml/trainingscreen/TrainingScreenMenuOverlay.qml deleted file mode 100644 index e0ca700..0000000 --- a/src/qml/trainingscreen/TrainingScreenMenuOverlay.qml +++ /dev/null @@ -1,182 +0,0 @@ -/* - * Copyright 2012 Sebastian Gottfried - * Copyright 2015 Sebastian Gottfried - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License as - * published by the Free Software Foundation; either version 2 of - * the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -import QtQuick 2.9 -import QtQuick.Controls 1.3 -import QtQuick.Layouts 1.3 -import QtGraphicalEffects 1.0 -import ktouch 1.0 - -Loader { - id: loader - - property Item blurSource; - - signal closed() - signal restartRequested() - signal abortRequested() - - active: false - - function show() { - loader.active = true - } - - function hide() { - item.opacity = 0 - } - - sourceComponent: Component { - FocusScope { - id: item - anchors.fill: parent - - opacity: loader.status == Loader.Ready? 1: 0 - - Component.onCompleted: resumeButton.forceActiveFocus() - - Behavior on opacity { - SequentialAnimation { - NumberAnimation { - duration: 300 - easing.type: Easing.InOutQuad - } - ScriptAction { - script: { - if (opacity == 0) { - loader.active = false; - closed() - } - } - } - } - } - - - ShaderEffectSource { - id: effectSource - sourceItem: blurSource - anchors.fill: parent - hideSource: false - } - - HueSaturation { - id: desaturatedBackground - source: effectSource - anchors.fill: parent - lightness: -0.3 - saturation: -0.5 - visible: false - } - - FastBlur { - anchors.fill: parent - source: desaturatedBackground - radius: 50 - } - - Rectangle { - anchors.fill: parent - color: "#55000000" - } - - /* swallow all mouse events */ - MouseArea { - anchors.fill: parent - enabled: false - hoverEnabled: enabled - } - - - GroupBox { - id: groupBox - anchors.centerIn: parent - width: column.width + 30 - height: column.height + 30 - - Column { - id: column - focus: true - anchors.centerIn: parent - spacing: 15 - width: Math.max(resumeButton.implicitWidth, restartButton.implicitWidth, returnButton.implicitWidth) - - Button { - id: resumeButton - iconName: "go-next-view" - text: i18n("Resume Training") - width: parent.width - onClicked: hide() - KeyNavigation.backtab: returnButton - KeyNavigation.tab: restartButton - KeyNavigation.down: restartButton - } - - Button { - id: restartButton - iconName: "view-refresh" - text: i18n("Restart Lesson") - width: parent.width - onClicked: { - restartRequested() - hide() - } - KeyNavigation.backtab: resumeButton - KeyNavigation.tab: returnButton - KeyNavigation.up: resumeButton - KeyNavigation.down: returnButton - } - - Button { - id: returnButton - iconName: "go-home" - text: i18n("Return to Home Screen") - width: parent.width - onClicked: { - hide() - abortRequested() - } - KeyNavigation.backtab: restartButton - KeyNavigation.tab: resumeButton - KeyNavigation.up: restartButton - } - - Keys.onDownPressed: { - if (resumeButton.focus) - restartButton.focus = true; - else if (restartButton.focus) - returnButton.focus = true; - } - - Keys.onUpPressed: { - if (restartButton.focus) - resumeButton.focus = true; - else if (returnButton.focus) - restartButton.focus = true; - } - - Keys.onEscapePressed: { - hide() - } - } - } - } - - } -} - diff --git a/src/qml/trainingscreen/TrainingScreenToolbar.qml b/src/qml/trainingscreen/TrainingScreenToolbar.qml index 95340ca..5ad44b5 100644 --- a/src/qml/trainingscreen/TrainingScreenToolbar.qml +++ b/src/qml/trainingscreen/TrainingScreenToolbar.qml @@ -1,81 +1,80 @@ /* - * Copyright 2012 Sebastian Gottfried - * Copyright 2015 Sebastian Gottfried + * Copyright 2018 Sebastian Gottfried * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.9 -import QtQuick.Controls 1.3 import QtQuick.Layouts 1.3 import ktouch 1.0 import "../common" -Item { - id: item +ToolBar { + id: root property TrainingStats stats property bool trainingStarted: false property bool trainingFinished: true - property Item menuOverlayItem + property PopupDialog menu + + dimFactor: 1.8 function setMessage() { if (!stats.timeIsRunning && !trainingFinished) { var msg = trainingStarted? i18n("Training session started. Time begins running with the first keystroke."): i18n("Training session interrupted. Time begins running again with next keystroke.") messageBox.showMessage(msg, "media-playback-pause") } else { messageBox.clearMessage() } } function reset() { messageBox.clearMessageImmediately() } onTrainingStartedChanged: setMessage() onTrainingFinishedChanged: setMessage() Connections { target: stats onTimeIsRunningChanged: setMessage() } Row { anchors { verticalCenter: parent.verticalCenter left: parent.left right: parent.right leftMargin: 30 rightMargin: 30 - verticalCenterOffset: -1 } - spacing: 3 - height: menuButton.height + spacing: 5 - ToolButton { + IconToolButton { id: menuButton iconName: "go-home" - onClicked: item.menuOverlayItem.show() + onClicked: root.menu.open() + colorScheme: root.colorScheme } MessageBox { id: messageBox } } } diff --git a/src/qml/trainingscreen/TrainingWidget.qml b/src/qml/trainingscreen/TrainingWidget.qml index bc5b56e..b0236fe 100644 --- a/src/qml/trainingscreen/TrainingWidget.qml +++ b/src/qml/trainingscreen/TrainingWidget.qml @@ -1,246 +1,246 @@ /* - * Copyright 2013 Sebastian Gottfried + * Copyright 2018 Sebastian Gottfried * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as * published by the Free Software Foundation; either version 2 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ import QtQuick 2.9 -import QtQuick.Controls 1.3 import ktouch 1.0 import "../keyboard" +import "../common" FocusScope { id: trainingWidget property Lesson lesson property KeyboardLayout keyboardLayout property TrainingStats trainingStats property Item overlayContainer property alias nextChar: trainingLine.nextCharacter property alias isCorrect: trainingLine.isCorrect property int position: -1 signal finished signal keyPressed(variant event) signal keyReleased(variant event) function reset() { stats.reset() lessonPainter.reset() sheetFlick.scrollToCurrentLine() trainingLine.active = true } function forceActiveFocus() { trainingLine.forceActiveFocus() } Timer { id: stopTimer interval: 5000 onTriggered: { stats.stopTraining() } } MouseArea { anchors.fill: parent onClicked: trainingLine.forceActiveFocus() } ScrollView { anchors.fill: parent Flickable { id: sheetFlick anchors.fill: parent contentWidth: parent.width contentHeight: sheet.height + 60 clip: true flickableDirection: Flickable.VerticalFlick function currentLineY() { var cursorRect = lessonPainter.cursorRectangle var y = cursorRect.y + sheet.y + (cursorRect.height / 2) return Math.max(Math.min((y - (height / 2)), contentHeight - height), 0) } function scrollToCurrentLine() { scrollAnimation.to = currentLineY() scrollAnimation.start() } onHeightChanged: { contentY = currentLineY() } NumberAnimation { target: sheetFlick id: scrollAnimation duration: 150 property: "contentY" } Rectangle { id: sheet color: "#fff" x: 30 y: 30 width: trainingWidget.width - 60 height: lessonPainter.height border { width: 1 color: "#000" } LessonPainter { id: lessonPainter anchors.centerIn: sheet lesson: trainingWidget.lesson maximumWidth: parent.width trainingLineCore: trainingLine onDone: { trainingLine.active = false trainingWidget.finished(); stats.stopTraining(); } TrainingLineCore { id: trainingLine anchors.fill: parent focus: true trainingStats: stats cursorItem: cursor onActiveFocusChanged: { if (!trainingLine.activeFocus) { trainingStats.stopTraining() } } Keys.onPressed: { if (!trainingLine.active) return cursorAnimation.restart() trainingStats.startTraining() stopTimer.restart() if (!event.isAutoRepeat) { trainingWidget.keyPressed(event) } } Keys.onReleased: { if (!trainingLine.active) return if (!event.isAutoRepeat) { trainingWidget.keyReleased(event) } } KeyNavigation.backtab: trainingLine KeyNavigation.tab: trainingLine } Rectangle { id: cursor color: "#000" x: Math.floor(lessonPainter.cursorRectangle.x) y: lessonPainter.cursorRectangle.y width: lessonPainter.cursorRectangle.width height: lessonPainter.cursorRectangle.height onYChanged: sheetFlick.scrollToCurrentLine() SequentialAnimation { id: cursorAnimation running: trainingLine.active && trainingLine.activeFocus && Qt.application.active loops: Animation.Infinite PropertyAction { target: cursor property: "opacity" value: 1 } PauseAnimation { duration: 500 } PropertyAction { target: cursor property: "opacity" value: 0 } PauseAnimation { duration: 500 } } } } } } } KeyItem { id: hintKey parent: trainingWidget.overlayContainer anchors.horizontalCenter: parent.horizontalCenter y: Math.max(height, Math.min(parent.height - 2 * height, sheetFlick.mapToItem(parent, 0, cursor.y + 3 * cursor.height - sheetFlick.contentY).y)) property real horizontalScaleFactor: 1 property real verticalScaleFactor: 1 property Key defaultKey: Key {} property KeyboardLayout defaultKeyboardLayout: KeyboardLayout {} key: { var specialKeyType switch (trainingLine.hintKey) { case Qt.Key_Return: specialKeyType = SpecialKey.Return break case Qt.Key_Backspace: specialKeyType = SpecialKey.Backspace break case Qt.Key_Space: specialKeyType = SpecialKey.Space break default: specialKeyType = -1 } for (var i = 0; i < keyboardLayout.keyCount; i++) { var key = keyboardLayout.key(i) if (key.keyType() === "specialKey" && key.type === specialKeyType) { return key; } } return defaultKey } opacity: trainingLine.hintKey !== -1? 1: 0 isHighlighted: opacity == 1 keyboardLayout: screen.keyboardLayout || defaultKeyboardLayout Behavior on opacity { NumberAnimation { duration: 150 } } } }