1/* 2 * SPDX-FileCopyrightText: 2012 Sebastian Gottfried <sebastiangottfried@web.de> 3 * SPDX-FileCopyrightText: 2015 Sebastian Gottfried <sebastiangottfried@web.de> 4 * 5 * SPDX-License-Identifier: GPL-2.0-or-later 6 */ 7 8import QtQuick 2.9 9import QtGraphicalEffects 1.0 10import ktouch 1.0 11 12Item { 13 id: item 14 15 property int keyIndex 16 property KeyboardLayout keyboardLayout 17 property bool isHighlighted: false 18 property bool animateHighlight: true 19 property bool enabled: true 20 property bool pressed: false 21 property real horizontalScaleFactor: 1 22 property real verticalScaleFactor: 1 23 24 property AbstractKey key: item.keyboardLayout.key(item.keyIndex) 25 property AbstractKey referenceKey: keyboardLayout.referenceKey 26 27 function match(data) { 28 var eventText = data 29 var eventKey = -1 30 if (typeof data === "object") { 31 eventText = data.text 32 eventKey = data.key 33 } 34 if (typeof data === "number") { 35 eventText = "" 36 eventKey = data 37 } 38 switch (key.keyType()) { 39 case "key": 40 for (var i = 0; i < key.keyCharCount; i++) { 41 if (key.keyChar(i).value == eventText) { 42 return true; 43 } 44 } 45 return false 46 47 case "specialKey": 48 switch (key.type) { 49 case SpecialKey.Tab: 50 return eventKey == Qt.Key_Tab 51 case SpecialKey.Capslock: 52 return eventKey == Qt.Key_CapsLock 53 case SpecialKey.Shift: 54 return eventKey == Qt.Key_Shift 55 case SpecialKey.Backspace: 56 return eventKey == Qt.Key_Backspace 57 case SpecialKey.Return: 58 return eventKey == Qt.Key_Return 59 case SpecialKey.Space: 60 return eventKey == Qt.Key_Space || eventText == " " 61 } 62 return false 63 } 64 return false; 65 } 66 67 function getTint(color) { 68 color.a = preferences.fingerOpacity / 100; 69 return color 70 } 71 72 property color tint: key && key.keyType() == "key"? 73 getTint(preferences.fingerColor(key.fingerIndex)): 74 "#00000000" 75 76 x: Math.round(key.left * horizontalScaleFactor) 77 y: Math.round(key.top * verticalScaleFactor) 78 width: Math.round(key.width * horizontalScaleFactor) 79 height: Math.round(key.height * verticalScaleFactor) 80 81 state: enabled? (pressed? "pressed": "normal"): "disabled" 82 83 onIsHighlightedChanged: { 84 if (!animateHighlight) { 85 shadow.state = isHighlighted? "highlighted1": "normal" 86 } 87 } 88 89 Rectangle { 90 id: shadow 91 92 property int marginSize: 0 93 94 anchors.centerIn: parent 95 width: item.width + marginSize 96 height: item.height + marginSize 97 smooth: true 98 radius: body.radius 99 state: "normal" 100 101 states: [ 102 State { 103 name: "normal" 104 PropertyChanges { 105 target: shadow 106 color: "#000" 107 marginSize: 0 108 } 109 PropertyChanges { 110 target: shadowEffect 111 glowRadius: body.radius 112 } 113 }, 114 State { 115 name: "highlighted1" 116 PropertyChanges { 117 target: shadow 118 color: "#54A7F0" 119 marginSize: 4 120 } 121 PropertyChanges { 122 target: shadowEffect 123 glowRadius: 1.5 * body.radius 124 } 125 }, 126 State { 127 name: "highlighted2" 128 PropertyChanges { 129 target: shadow 130 color: "#54A7F0" 131 marginSize: 0 132 } 133 PropertyChanges { 134 target: shadowEffect 135 glowRadius: 1.5 * body.radius 136 } 137 } 138 ] 139 140 Behavior on marginSize { 141 enabled: animateHighlight 142 NumberAnimation { 143 duration: 150 144 easing.type: Easing.InOutQuad 145 } 146 } 147 148 Behavior on color { 149 enabled: animateHighlight 150 ColorAnimation { duration: 150 } 151 } 152 153 154 SequentialAnimation { 155 id: pulseAnimation 156 loops: Animation.Infinite 157 running: isHighlighted && animateHighlight 158 onRunningChanged: { 159 if (!running) 160 shadow.state = "normal" 161 } 162 163 ScriptAction { 164 script: shadow.state = "highlighted1" 165 } 166 PauseAnimation { duration: 850 } 167 ScriptAction { 168 script: shadow.state = "highlighted2" 169 } 170 PauseAnimation { duration: 150 } 171 } 172 } 173 174 RectangularGlow { 175 id: shadowEffect 176 anchors.fill: shadow 177 color: shadow.color 178 glowRadius: 5 179 cornerRadius: glowRadius + shadow.radius 180 181 Behavior on glowRadius { 182 enabled: animateHighlight 183 NumberAnimation { 184 duration: 150 185 easing.type: Easing.InOutQuad 186 } 187 } 188 } 189 190 Rectangle { 191 id: body 192 anchors.fill: parent 193 radius: Math.max(3, Math.min(referenceKey.height, referenceKey.width) / 10 * Math.min(horizontalScaleFactor, verticalScaleFactor)) 194 border.width: 1 195 border.color: "#000" 196 smooth: true 197 198 gradient: Gradient { 199 GradientStop { id: gradientStop0; position: 0.0; } 200 GradientStop { id: gradientStop1; position: 0.5; } 201 GradientStop { id: gradientStop2; position: 1.0; } 202 } 203 204 Rectangle { 205 id: hapticMarker 206 anchors { 207 bottom: parent.bottom 208 horizontalCenter: parent.horizontalCenter 209 bottomMargin: 4 210 } 211 visible: item.key.keyType() == "key" && item.key.hasHapticMarker 212 height: 3 213 width: body.width / 3 214 radius: 1 215 color: topLeftLabel.color 216 border { 217 width: 1 218 color: topLeftLabel.color 219 } 220 } 221 } 222 223 Item { 224 anchors.topMargin: Math.max(referenceKey.width / 20, 3) * verticalScaleFactor 225 anchors.bottomMargin: anchors.topMargin 226 anchors.leftMargin: Math.max(referenceKey.width / 10, 5) * horizontalScaleFactor 227 anchors.rightMargin: anchors.leftMargin 228 anchors.fill: parent 229 KeyLabel { 230 id: topLeftLabel 231 key: item.key 232 position: KeyChar.TopLeft 233 } 234 KeyLabel { 235 id: topRightLabel 236 anchors.right: parent.right 237 key: item.key 238 position: KeyChar.TopRight 239 } 240 KeyLabel { 241 id: bottomLeftLabel 242 anchors.bottom: parent.bottom 243 key: item.key 244 position: KeyChar.BottomLeft 245 } 246 KeyLabel { 247 id: bottomRightLabel 248 anchors.right: parent.right 249 anchors.bottom: parent.bottom 250 key: item.key 251 position: KeyChar.BottomRight 252 } 253 } 254 255 states: [ 256 State { 257 name: "normal" 258 PropertyChanges { 259 target: gradientStop0 260 color: Qt.tint("#f0f0f0", item.tint) 261 } 262 PropertyChanges { 263 target: gradientStop1 264 color: Qt.tint("#d5d5d5", item.tint) 265 } 266 PropertyChanges { 267 target: gradientStop2 268 color: Qt.tint("#ccc", item.tint) 269 } 270 }, 271 State { 272 name: "pressed" 273 PropertyChanges { 274 target: gradientStop0 275 color: Qt.tint("#666", item.tint) 276 } 277 PropertyChanges { 278 target: gradientStop1 279 color: Qt.tint("#888", item.tint) 280 } 281 PropertyChanges { 282 target: gradientStop2 283 color: Qt.tint("#999", item.tint) 284 } 285 }, 286 State { 287 name: "disabled" 288 PropertyChanges { 289 target: gradientStop0 290 color: Qt.tint("#444", item.tint) 291 } 292 PropertyChanges { 293 target: gradientStop1 294 color: Qt.tint("#333", item.tint) 295 } 296 PropertyChanges { 297 target: gradientStop2 298 color: Qt.tint("#222", item.tint) 299 } 300 } 301 ] 302} 303