diff --git a/quickshell/Modules/Lock/LockScreenContent.qml b/quickshell/Modules/Lock/LockScreenContent.qml index 03800fa56..831039401 100644 --- a/quickshell/Modules/Lock/LockScreenContent.qml +++ b/quickshell/Modules/Lock/LockScreenContent.qml @@ -846,6 +846,13 @@ Item { cursorPosition -= 1; } + function deleteForward() { + clampCursorPosition(); + if (cursorPosition === text.length) + return; + text = text.slice(0, cursorPosition) + text.slice(cursorPosition + 1); + } + function isPrintableText(value) { if (value.length === 0) return false; @@ -915,16 +922,38 @@ Item { return; } - if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) { + switch (event.key) { + case Qt.Key_Return: + case Qt.Key_Enter: accepted(); event.accepted = true; return; - } - - if (event.key === Qt.Key_Backspace) { + case Qt.Key_Backspace: backspace(); event.accepted = true; return; + case Qt.Key_Delete: + deleteForward(); + event.accepted = true; + return; + case Qt.Key_Left: + clampCursorPosition(); + cursorPosition = Math.max(0, cursorPosition - 1); + event.accepted = true; + return; + case Qt.Key_Right: + clampCursorPosition(); + cursorPosition = Math.min(text.length, cursorPosition + 1); + event.accepted = true; + return; + case Qt.Key_Home: + cursorPosition = 0; + event.accepted = true; + return; + case Qt.Key_End: + cursorPosition = text.length; + event.accepted = true; + return; } if (isPrintableText(event.text)) { @@ -1028,6 +1057,8 @@ Item { } StyledText { + id: passwordDisplay + anchors.left: lockIconContainer.right anchors.leftMargin: Theme.spacingM anchors.right: (revealButton.visible ? revealButton.left : (virtualKeyboardButton.visible ? virtualKeyboardButton.left : (securityKeyButton.visible ? securityKeyButton.left : (enterButton.visible ? enterButton.left : (loadingSpinner.visible ? loadingSpinner.left : parent.right))))) @@ -1057,6 +1088,33 @@ Item { } } + TextMetrics { + id: passwordCursorMetrics + font: passwordDisplay.font + text: passwordDisplay.text.slice(0, passwordField.cursorPosition) + } + + DankTextCursor { + id: passwordCursor + + x: passwordDisplay.x + passwordCursorMetrics.advanceWidth + Math.min(0, passwordDisplay.width - passwordDisplay.implicitWidth) + anchors.verticalCenter: parent.verticalCenter + height: passwordDisplay.font.pixelSize + 4 + shown: !demoMode && passwordField.activeFocus && !pam.passwd.active && !pam.u2fPending && !root.unlocking + + Connections { + target: passwordField + + function onCursorPositionChanged() { + passwordCursor.resetBlink(); + } + + function onTextChanged() { + passwordCursor.resetBlink(); + } + } + } + DankActionButton { id: revealButton diff --git a/quickshell/Modules/Notepad/NotepadTextEditor.qml b/quickshell/Modules/Notepad/NotepadTextEditor.qml index ac48ecfcc..c69b2f713 100644 --- a/quickshell/Modules/Notepad/NotepadTextEditor.qml +++ b/quickshell/Modules/Notepad/NotepadTextEditor.qml @@ -598,29 +598,20 @@ Column { topPadding: Theme.spacingM rightPadding: Theme.spacingM bottomPadding: Theme.spacingM - cursorDelegate: Rectangle { + cursorDelegate: DankTextCursor { + id: notepadCursor width: 1.5 - radius: 1 color: Theme.surfaceText x: textArea.cursorRectangle.x y: textArea.cursorRectangle.y height: textArea.cursorRectangle.height - opacity: 1.0 + shown: textArea.cursorVisible - SequentialAnimation on opacity { - running: textArea.activeFocus - loops: Animation.Infinite - OpacityAnimator { - from: 1.0 - to: 0.0 - duration: 650 - easing.type: Easing.InOutQuad - } - OpacityAnimator { - from: 0.0 - to: 1.0 - duration: 650 - easing.type: Easing.InOutQuad + Connections { + target: textArea + + function onCursorPositionChanged() { + notepadCursor.resetBlink(); } } } diff --git a/quickshell/Widgets/DankTextCursor.qml b/quickshell/Widgets/DankTextCursor.qml new file mode 100644 index 000000000..71a18b734 --- /dev/null +++ b/quickshell/Widgets/DankTextCursor.qml @@ -0,0 +1,31 @@ +import QtQuick +import qs.Common + +Rectangle { + id: root + + property bool shown: true + property bool blinkOn: true + + readonly property int flashTime: Qt.styleHints.cursorFlashTime + + function resetBlink() { + blinkOn = true; + blinkTimer.restart(); + } + + width: 2 + radius: 1 + color: Theme.primary + visible: shown && blinkOn + + onShownChanged: resetBlink() + + Timer { + id: blinkTimer + running: root.shown && root.flashTime > 1 + interval: root.flashTime / 2 + repeat: true + onTriggered: root.blinkOn = !root.blinkOn + } +}