diff --git a/src/qml/keyboard/KeyItem.qml b/src/qml/keyboard/KeyItem.qml index 9404189..cabae92 100644 --- a/src/qml/keyboard/KeyItem.qml +++ b/src/qml/keyboard/KeyItem.qml @@ -1,310 +1,313 @@ /* * 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.4 import QtGraphicalEffects 1.0 import ktouch 1.0 Item { id: item property int keyIndex property KeyboardLayout keyboardLayout property bool isHighlighted: false property bool animateHighlight: true property bool enabled: true property bool pressed: false + property real horizontalScaleFactor: 1 + property real verticalScaleFactor: 1 property AbstractKey key: item.keyboardLayout.key(item.keyIndex) property AbstractKey referenceKey: keyboardLayout.referenceKey function match(data) { var eventText = data var eventKey = -1 if (typeof data === "object") { eventText = data.text eventKey = data.key } if (typeof data === "number") { eventText = "" eventKey = data } switch (key.keyType()) { case "key": for (var i = 0; i < key.keyCharCount; i++) { if (key.keyChar(i).value == eventText) { return true; } } return false case "specialKey": switch (key.type) { case SpecialKey.Tab: return eventKey == Qt.Key_Tab case SpecialKey.Capslock: return eventKey == Qt.Key_CapsLock case SpecialKey.Shift: return eventKey == Qt.Key_Shift case SpecialKey.Backspace: return eventKey == Qt.Key_Backspace case SpecialKey.Return: return eventKey == Qt.Key_Return case SpecialKey.Space: return eventKey == Qt.Key_Space || eventText == " " } return false } return false; } function getTint(color) { color.a = 0.125 return color } property color tint: key && key.keyType() == "key"? getTint(preferences.fingerColor(key.fingerIndex)): "#00000000" x: Math.round(key.left * horizontalScaleFactor) y: Math.round(key.top * verticalScaleFactor) width: Math.round(key.width * horizontalScaleFactor) height: Math.round(key.height * verticalScaleFactor) state: enabled? (pressed? "pressed": "normal"): "disabled" onIsHighlightedChanged: { if (!animateHighlight) { shadow.state = isHighlighted? "highlighted1": "normal" } } Rectangle { id: shadow property int marginSize: 0 anchors.centerIn: parent width: item.width + marginSize height: item.height + marginSize smooth: true radius: body.radius state: "normal" states: [ State { name: "normal" PropertyChanges { target: shadow color: "#000" marginSize: 0 } PropertyChanges { target: shadowEffect glowRadius: 10 } }, State { name: "highlighted1" PropertyChanges { target: shadow color: "#54A7F0" marginSize: 4 } PropertyChanges { target: shadowEffect glowRadius: 15 } }, State { name: "highlighted2" PropertyChanges { target: shadow color: "#54A7F0" marginSize: 0 } PropertyChanges { target: shadowEffect glowRadius: 15 } } ] Behavior on marginSize { enabled: animateHighlight NumberAnimation { duration: 150 easing.type: Easing.InOutQuad } } Behavior on color { enabled: animateHighlight ColorAnimation { duration: 150 } } SequentialAnimation { id: pulseAnimation loops: Animation.Infinite running: isHighlighted && animateHighlight onRunningChanged: { if (!running) shadow.state = "normal" } ScriptAction { script: shadow.state = "highlighted1" } PauseAnimation { duration: 850 } ScriptAction { script: shadow.state = "highlighted2" } PauseAnimation { duration: 150 } } } RectangularGlow { id: shadowEffect anchors.fill: shadow color: shadow.color glowRadius: 5 + cornerRadius: glowRadius + shadow.radius Behavior on glowRadius { enabled: animateHighlight NumberAnimation { duration: 150 easing.type: Easing.InOutQuad } } } Rectangle { id: body anchors.fill: parent radius: Math.max(3, Math.min(referenceKey.height, referenceKey.width) / 10 * Math.min(horizontalScaleFactor, verticalScaleFactor)) border.width: 1 border.color: "#000" smooth: true gradient: Gradient { GradientStop { id: gradientStop0; position: 0.0; } GradientStop { id: gradientStop1; position: 0.5; } GradientStop { id: gradientStop2; position: 1.0; } } Rectangle { id: hapticMarker anchors { bottom: parent.bottom horizontalCenter: parent.horizontalCenter bottomMargin: 4 } visible: item.key.keyType() == "key" && item.key.hasHapticMarker height: 3 width: body.width / 3 radius: 1 color: topLeftLabel.color border { width: 1 color: topLeftLabel.color } } } Item { - anchors.topMargin: Math.max(referenceKey.width / 20, 3 * verticalScaleFactor) + anchors.topMargin: Math.max(referenceKey.width / 20, 3) * verticalScaleFactor anchors.bottomMargin: anchors.topMargin - anchors.leftMargin: Math.max(referenceKey.width / 10, 5 * horizontalScaleFactor) + anchors.leftMargin: Math.max(referenceKey.width / 10, 5) * horizontalScaleFactor anchors.rightMargin: anchors.leftMargin anchors.fill: parent KeyLabel { id: topLeftLabel key: item.key position: KeyChar.TopLeft } KeyLabel { id: topRightLabel anchors.right: parent.right key: item.key position: KeyChar.TopRight } KeyLabel { id: bottomLeftLabel anchors.bottom: parent.bottom key: item.key position: KeyChar.BottomLeft } KeyLabel { id: bottomRightLabel anchors.right: parent.right anchors.bottom: parent.bottom key: item.key position: KeyChar.BottomRight } } states: [ State { name: "normal" PropertyChanges { target: gradientStop0 color: Qt.tint("#f0f0f0", item.tint) } PropertyChanges { target: gradientStop1 color: Qt.tint("#d5d5d5", item.tint) } PropertyChanges { target: gradientStop2 color: Qt.tint("#ccc", item.tint) } }, State { name: "pressed" PropertyChanges { target: gradientStop0 color: Qt.tint("#666", item.tint) } PropertyChanges { target: gradientStop1 color: Qt.tint("#888", item.tint) } PropertyChanges { target: gradientStop2 color: Qt.tint("#999", item.tint) } }, State { name: "disabled" PropertyChanges { target: gradientStop0 color: Qt.tint("#444", item.tint) } PropertyChanges { target: gradientStop1 color: Qt.tint("#333", item.tint) } PropertyChanges { target: gradientStop2 color: Qt.tint("#222", item.tint) } } ] } diff --git a/src/qml/keyboard/Keyboard.qml b/src/qml/keyboard/Keyboard.qml index 295257a..ecb2252 100644 --- a/src/qml/keyboard/Keyboard.qml +++ b/src/qml/keyboard/Keyboard.qml @@ -1,97 +1,99 @@ /* * Copyright 2013 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.4 import ktouch 1.0 Item { id: keyboard signal keyboardUpdate property KeyboardLayout keyboardLayout property real aspectRatio: keyboardLayout.width / keyboardLayout.height property real horizontalScaleFactor: width / keyboardLayout.width property real verticalScaleFactor: height / keyboardLayout.height function keyItems() { var items = [] for (var i = 0; i < keys.count; i++) { items.push(keys.itemAt(i)) } return items } function findKeyItems(keyChar) { var matchingKeys = [] for (var i = 0; i < keys.count; i++) { var key = keys.itemAt(i); if (key.match(keyChar)) matchingKeys.push(key) } return matchingKeys } function findModifierKeyItem(modifierId) { for (var i = 0; i < keys.count; i++) { var key = keys.itemAt(i); if (key.key.keyType() === "specialKey" && key.key.modifierId === modifierId) return key } return null } function handleKeyPress(event) { var eventKeys = findKeyItems(event) for (var i = 0; i < eventKeys.length; i++) { eventKeys[i].pressed = true } } function handleKeyRelease(event) { var eventKeys = findKeyItems(event) for (var i = 0; i < eventKeys.length; i++) { eventKeys[i].pressed = false } } Item { id: keyContainer width: childrenRect.width height: childrenRect.height anchors.centerIn: parent Repeater { id: keys model: keyboard.visible && keyboardLayout.isValid? keyboard.keyboardLayout.keyCount: 0 onModelChanged: keyboard.keyboardUpdate() KeyItem { keyboardLayout: keyboard.keyboardLayout; keyIndex: index + horizontalScaleFactor: keyboard.horizontalScaleFactor + verticalScaleFactor: keyboard.verticalScaleFactor } } } } diff --git a/src/qml/keyboard/KeyboardLayoutEditor.qml b/src/qml/keyboard/KeyboardLayoutEditor.qml index b2eca64..00da56b 100644 --- a/src/qml/keyboard/KeyboardLayoutEditor.qml +++ b/src/qml/keyboard/KeyboardLayoutEditor.qml @@ -1,114 +1,114 @@ /* * Copyright 2012 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.4 import ktouch 1.0 import "../common" Item { id: root Preferences { id: preferences } property real scaleFactor: Math.pow(2, keyboardLayoutEditor.zoomLevel / 2) - property real horizontalScaleFactor: scaleFactor - property real verticalScaleFactor: scaleFactor property KeyboardLayout layout: keyboardLayoutEditor.keyboardLayout property int lastZIndex: 0 width: keyContainer.width + 40 height: keyContainer.height + 40 MouseArea { anchors.fill: parent onPressed: { if (mouse.button == Qt.LeftButton) { keyboardLayoutEditor.selectedKey = null mouse.accepted = true } } } Grid { id: keyContainer anchors.centerIn: parent width: Math.round(layout.width * scaleFactor) height: Math.round(layout.height * scaleFactor) lineDistance: 10.0 * scaleFactor color: "#121286" backgroundColor: "#cccccc" Repeater { id: keys model: layout.isValid? layout.keyCount: 0 KeyItem { property bool manipulated: false id: keyItem keyboardLayout: layout; keyIndex: index isHighlighted: keyItem.key == keyboardLayoutEditor.selectedKey animateHighlight: false opacity: manipulated? 0.7: 1.0 + horizontalScaleFactor: scaleFactor + verticalScaleFactor: scaleFactor MouseArea { anchors.fill: parent cursorShape: keyItem.manipulated? Qt.SizeAllCursor: Qt.ArrowCursor onPressed: { if (mouse.button == Qt.LeftButton) { keyboardLayoutEditor.selectedKey = layout.key(index) root.lastZIndex++ keyItem.z = root.lastZIndex } } drag { target: !keyboardLayoutEditor.readOnly? keyItem: undefined axis: Drag.XandYAxis minimumX: 0 maximumX: keyContainer.width - keyItem.width minimumY: 0 maximumY: keyContainer.height - keyItem.height onActiveChanged: { keyItem.manipulated = drag.active if (!drag.active) { var left = 10 * Math.round(keyItem.x / scaleFactor / 10) var top = 10 * Math.round(keyItem.y / scaleFactor / 10) keyboardLayoutEditor.setKeyGeometry(keyIndex, left, top, keyItem.key.width, keyItem.key.height) } } } } Behavior on opacity { NumberAnimation { duration: 150 } } } } SelectionRectangle { keyboardLayout: layout; target: keyboardLayoutEditor.selectedKey z: root.lastZIndex + 1 interactive: !keyboardLayoutEditor.readOnly } } } diff --git a/src/qml/trainingscreen/TrainingWidget.qml b/src/qml/trainingscreen/TrainingWidget.qml index 4852549..bd29820 100644 --- a/src/qml/trainingscreen/TrainingWidget.qml +++ b/src/qml/trainingscreen/TrainingWidget.qml @@ -1,246 +1,244 @@ /* * Copyright 2013 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.4 import QtQuick.Controls 1.3 import ktouch 1.0 import "../keyboard" 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 } } } }