// Config created by Keyitdev https://git.rp1.hu/gabeszm/sddm-rave-theme // Copyright (C) 2022-2025 Keyitdev // Based on https://github.com/MarianArlt/sddm-sugar-dark // Distributed under the GPLv3+ License https://www.gnu.org/licenses/gpl-3.0.html import QtQuick 2.15 import QtQuick.Layouts 6.5 import QtQuick.Controls 2.15 import QtQuick.Effects 6.5 Column { id: inputContainer width: parent.width Layout.fillWidth: true clip: true property ComboBox exposeSession: sessionSelect.exposeSession property bool failed Item { id: errorMessageField // change also in selectSession height: root.font.pointSize * 2 width: parent.width anchors.horizontalCenter: parent.horizontalCenter Label { id: errorMessage width: parent.width horizontalAlignment: Text.AlignHCenter text: failed ? config.TranslateLoginFailedWarning || textConstants.loginFailed + "!" : keyboard.capsLock ? config.TranslateCapslockWarning || textConstants.capslockWarning : null font.pointSize: root.font.pointSize * 0.8 font.italic: true color: config.WarningColor opacity: 0 states: [ State { name: "fail" when: failed PropertyChanges { target: errorMessage opacity: 1 } }, State { name: "capslock" when: keyboard.capsLock PropertyChanges { target: errorMessage opacity: 1 } } ] transitions: [ Transition { PropertyAnimation { properties: "opacity" duration: 100 } } ] } } // Profilkép Item { id: avatarField height: Math.min(root.font.pointSize * 6.5, parent.width * 0.35) width: parent.width anchors.horizontalCenter: parent.horizontalCenter property int currentAttempt: 0 property var candidateIcons: [] function resolveIconCandidates(idx, name) { var list = [] var count = (typeof userModel !== "undefined" && userModel) ? userModel.count : 0 var uIndex = -1 if (name && name !== "" && count > 0) { for (var i = 0; i < count; i++) { var qIdx = userModel.index(i, 0) var uName = userModel.data(qIdx, Qt.UserRole + 1) if (uName === name) { uIndex = i break } } } if (uIndex === -1) { uIndex = (idx >= 0 && idx < count) ? idx : (userModel && userModel.lastIndex >= 0 ? userModel.lastIndex : 0) } var directIcon = "" var home = "" var uName = name || "" if (count > 0 && uIndex >= 0 && uIndex < count) { var qIdx = userModel.index(uIndex, 0) directIcon = userModel.data(qIdx, Qt.UserRole + 4) || "" home = userModel.data(qIdx, Qt.UserRole + 3) || "" if (!uName || uName === "") { uName = userModel.data(qIdx, Qt.UserRole + 1) || "" } } function addCandidate(p) { if (!p || p === "") return var s = p.toString().trim() if (s === "") return // Ignore generic silhouette icon installed in SDDM faces directory if (s === "/usr/share/sddm/faces/.face.icon" || s === "file:///usr/share/sddm/faces/.face.icon") return var url = (s.startsWith("file://") || s.startsWith("image://") || s.startsWith("qrc://") || s.startsWith("http")) ? s : ("file://" + s) if (list.indexOf(url) === -1) { list.push(url) } } // 1. Direct icon reported by SDDM (AccountsService or explicit face config) if (directIcon !== "") { addCandidate(directIcon) } // 2. AccountsService system icons (standard across Linux - world-readable 644) if (uName !== "") { addCandidate("/var/lib/AccountsService/icons/" + uName) addCandidate("/var/lib/AccountsService/icons/" + uName + ".png") addCandidate("/var/lib/AccountsService/icons/" + uName + ".jpg") addCandidate("/var/lib/AccountsService/icons/" + uName + ".jpeg") addCandidate("/var/lib/AccountsService/icons/" + uName + ".svg") } // 3. User's home directory faces if (home !== "") { addCandidate(home + "/.face") addCandidate(home + "/.face.icon") addCandidate(home + "/.face.png") addCandidate(home + "/.face.jpg") addCandidate(home + "/.face.jpeg") addCandidate(home + "/.icon") addCandidate(home + "/.avatar") } if (uName !== "") { addCandidate("/home/" + uName + "/.face") addCandidate("/home/" + uName + "/.face.icon") addCandidate("/home/" + uName + "/.face.png") addCandidate("/home/" + uName + "/.face.jpg") addCandidate("/home/" + uName + "/.face.jpeg") addCandidate("/home/" + uName + "/.icon") addCandidate("/home/" + uName + "/.avatar") } // 4. System SDDM faces directory if (uName !== "") { addCandidate("/usr/share/sddm/faces/" + uName + ".face.icon") addCandidate("/usr/share/sddm/faces/" + uName + ".png") addCandidate("/usr/share/sddm/faces/" + uName + ".jpg") addCandidate("/usr/share/sddm/faces/" + uName) addCandidate("/var/lib/sddm/faces/" + uName + ".face.icon") addCandidate("/var/lib/sddm/faces/" + uName + ".png") addCandidate("/var/lib/sddm/faces/" + uName + ".jpg") addCandidate("/var/lib/sddm/faces/" + uName) } // 5. Configured theme avatar if (config.UserAvatar && config.UserAvatar !== "") { addCandidate(config.UserAvatar) } if (config.DefaultAvatar && config.DefaultAvatar !== "") { addCandidate(config.DefaultAvatar) } return list } function tryNextCandidate() { if (currentAttempt < candidateIcons.length) { var nextUrl = candidateIcons[currentAttempt] currentAttempt++ avatarPhoto.source = nextUrl } else { avatarPhoto.source = "" } } function updateAvatarSource() { var targetUser = usernameField.selectedUsername if (!targetUser && typeof userModel !== "undefined" && userModel && userModel.count > 0) { targetUser = usernameField.getInitialUsername() } candidateIcons = resolveIconCandidates(usernameField.selectedUserIndex, targetUser) currentAttempt = 0 avatarPhoto.source = "" if (candidateIcons.length > 0) { tryNextCandidate() } } Component.onCompleted: updateAvatarSource() Connections { target: usernameField function onSelectedUsernameChanged() { avatarField.updateAvatarSource() } function onSelectedUserIndexChanged() { avatarField.updateAvatarSource() } } Connections { target: (typeof userModel !== "undefined") ? userModel : null function onRowsInserted() { avatarField.updateAvatarSource() } function onModelReset() { avatarField.updateAvatarSource() } function onDataChanged() { avatarField.updateAvatarSource() } } // Avatar kör Item { anchors.centerIn: parent width: root.font.pointSize * 5.2 height: root.font.pointSize * 5.2 // Avatar drop shadow Rectangle { anchors.fill: parent anchors.topMargin: root.font.pointSize * 0.15 radius: width / 2 color: Qt.rgba(0, 0, 0, 0.30) } Rectangle { id: avatarCircle anchors.fill: parent radius: width / 2 clip: true color: Qt.rgba(1, 1, 1, 0.15) // The mask source Item { id: avatarMask anchors.fill: parent visible: false layer.enabled: true Rectangle { anchors.fill: parent radius: parent.width / 2 color: "black" } } Image { id: avatarPhoto anchors.fill: parent fillMode: Image.PreserveAspectCrop smooth: true mipmap: true visible: status === Image.Ready layer.enabled: true layer.effect: MultiEffect { maskEnabled: true maskSource: avatarMask } onStatusChanged: { if (status === Image.Error) { avatarField.tryNextCandidate() } } } Image { id: avatarFallback anchors.centerIn: parent width: parent.width * 0.55 height: parent.height * 0.55 source: Qt.resolvedUrl("../Assets/User.svg") fillMode: Image.PreserveAspectFit smooth: true visible: avatarPhoto.status !== Image.Ready opacity: 0.85 } // Draw the border on top of everything! Rectangle { anchors.fill: parent radius: parent.width / 2 color: "transparent" border.color: Qt.rgba(1, 1, 1, 0.40) border.width: root.font.pointSize * 0.12 } } } } Item { id: usernameField height: root.font.pointSize * 3.8 width: parent.width anchors.horizontalCenter: parent.horizontalCenter property int selectedUserIndex: (typeof userModel !== "undefined" && userModel && userModel.lastIndex >= 0) ? userModel.lastIndex : 0 property string selectedUsername: getInitialUsername() function getInitialUsername() { if (typeof userModel === "undefined" || !userModel || userModel.count === 0) return "" var idx = (userModel.lastIndex >= 0 && userModel.lastIndex < userModel.count) ? userModel.lastIndex : 0 var name = userModel.data(userModel.index(idx, 0), Qt.UserRole + 1) return (name !== undefined && name !== null) ? name.toString() : "" } function selectUserAt(idx) { if (typeof userModel === "undefined" || !userModel || idx < 0 || idx >= userModel.count) return selectedUserIndex = idx selectedUsername = userModel.data(userModel.index(idx, 0), Qt.UserRole + 1) || "" avatarField.updateAvatarSource() userDropdownPopup.close() password.forceActiveFocus() } Connections { target: (typeof userModel !== "undefined") ? userModel : null function onRowsInserted() { if (usernameField.selectedUsername === "" || usernameField.selectedUserIndex >= userModel.count) { usernameField.selectedUserIndex = (userModel.lastIndex >= 0 && userModel.lastIndex < userModel.count) ? userModel.lastIndex : 0 usernameField.selectedUsername = usernameField.getInitialUsername() } avatarField.updateAvatarSource() } function onModelReset() { usernameField.selectedUserIndex = (userModel.lastIndex >= 0 && userModel.lastIndex < userModel.count) ? userModel.lastIndex : 0 usernameField.selectedUsername = usernameField.getInitialUsername() avatarField.updateAvatarSource() } function onDataChanged() { usernameField.selectedUsername = usernameField.getInitialUsername() avatarField.updateAvatarSource() } } // Container button / click area Item { id: userSelectorButton anchors.centerIn: parent height: root.font.pointSize * 2.8 width: parent.width activeFocusOnTab: true Keys.onReturnPressed: userDropdownPopup.visible ? userDropdownPopup.close() : userDropdownPopup.open() Keys.onEnterPressed: userDropdownPopup.visible ? userDropdownPopup.close() : userDropdownPopup.open() Keys.onSpacePressed: userDropdownPopup.visible ? userDropdownPopup.close() : userDropdownPopup.open() Keys.onDownPressed: { if (!userDropdownPopup.visible) { password.forceActiveFocus() } } KeyNavigation.down: password // Background with drop shadow and frosted glass Item { anchors.fill: parent Rectangle { anchors.fill: parent anchors.topMargin: root.font.pointSize * 0.12 radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 color: Qt.rgba(0, 0, 0, 0.20) } Rectangle { anchors.fill: parent color: userSelectorMouseArea.pressed ? Qt.rgba(1, 1, 1, 0.25) : (userSelectorMouseArea.containsMouse || userSelectorButton.activeFocus ? Qt.rgba(1, 1, 1, 0.20) : Qt.rgba(1, 1, 1, 0.14)) border.color: userSelectorButton.activeFocus ? Qt.rgba(255, 255, 255, 0.75) : (userSelectorMouseArea.containsMouse ? Qt.rgba(255, 255, 255, 0.45) : Qt.rgba(255, 255, 255, 0.25)) border.width: userSelectorButton.activeFocus ? root.font.pointSize * 0.12 : root.font.pointSize * 0.08 radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 Behavior on color { ColorAnimation { duration: 150 } } Behavior on border.color { ColorAnimation { duration: 150 } } } } // Left Icon (User icon) Button { id: userFieldLeftIcon width: parent.height height: parent.height anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter enabled: false icon.source: Qt.resolvedUrl("../Assets/User.svg") icon.width: parent.height * 0.38 icon.height: parent.height * 0.38 icon.color: "#ffffff" background: Rectangle { color: "transparent" } } // Username display in the middle (Non-editable, clean text) Text { id: username anchors.centerIn: parent width: parent.width - userFieldLeftIcon.width * 2.2 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter elide: Text.ElideRight text: usernameField.selectedUsername color: config.LoginFieldTextColor font.bold: true font.pointSize: root.font.pointSize * 0.95 font.family: root.font.family style: Text.Raised styleColor: Qt.rgba(0, 0, 0, 0.40) } // Dropdown Arrow Button on Right Item { id: userDropdownBtn width: parent.height height: parent.height anchors.right: parent.right anchors.verticalCenter: parent.verticalCenter Canvas { id: chevronCanvas width: root.font.pointSize * 0.85 height: root.font.pointSize * 0.50 anchors.centerIn: parent rotation: userDropdownPopup.visible ? 180 : 0 Behavior on rotation { NumberAnimation { duration: 200; easing.type: Easing.OutCubic } } onPaint: { var ctx = getContext("2d"); ctx.reset(); ctx.clearRect(0, 0, width, height); ctx.strokeStyle = userSelectorMouseArea.containsMouse ? "#ffffff" : "rgba(255, 255, 255, 0.85)"; ctx.lineWidth = Math.max(1.5, root.font.pointSize * 0.12); ctx.lineCap = "round"; ctx.lineJoin = "round"; ctx.beginPath(); ctx.moveTo(1.5, 1.5); ctx.lineTo(width / 2, height - 1.5); ctx.lineTo(width - 1.5, 1.5); ctx.stroke(); } Connections { target: userSelectorMouseArea function onContainsMouseChanged() { chevronCanvas.requestPaint(); } } } } // Whole field click area MouseArea { id: userSelectorMouseArea anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { if (userDropdownPopup.visible) { userDropdownPopup.close(); } else { userDropdownPopup.open(); } } } } // Dropdown Popup Popup { id: userDropdownPopup width: parent.width y: parent.height + root.font.pointSize * 0.4 x: 0 padding: root.font.pointSize * 0.5 dim: false closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutsideParent z: 100 background: Item { // Drop shadow underlay Rectangle { anchors.fill: parent anchors.topMargin: root.font.pointSize * 0.15 radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 color: Qt.rgba(0, 0, 0, 0.40) } // Frosted Glass body (minimally translucent) Rectangle { anchors.fill: parent radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 border.color: Qt.rgba(1, 1, 1, 0.40) border.width: 1 clip: true gradient: Gradient { GradientStop { position: 0.0; color: Qt.rgba(0.18, 0.20, 0.28, 0.92) } GradientStop { position: 0.5; color: Qt.rgba(0.14, 0.16, 0.24, 0.94) } GradientStop { position: 1.0; color: Qt.rgba(0.11, 0.13, 0.20, 0.96) } } } } contentItem: ListView { id: userDropdownList implicitHeight: Math.min(contentHeight, root.font.pointSize * 16) clip: true model: userModel spacing: root.font.pointSize * 0.25 boundsBehavior: Flickable.StopAtBounds delegate: Item { id: userDelegateItem width: userDropdownList.width height: root.font.pointSize * 3.4 property var itemCandidates: avatarField.resolveIconCandidates(index, model.name) property int itemAttempt: 0 property bool isSelected: index === usernameField.selectedUserIndex function tryNextItemCandidate() { if (itemAttempt < itemCandidates.length) { var nextUrl = itemCandidates[itemAttempt] itemAttempt++ dPhoto.source = nextUrl } else { dPhoto.source = "" } } Component.onCompleted: { itemAttempt = 0 dPhoto.source = "" if (itemCandidates.length > 0) { tryNextItemCandidate() } } Rectangle { anchors.fill: parent radius: root.font.pointSize * 0.6 color: userDelegateMouse.pressed ? Qt.rgba(1, 1, 1, 0.24) : userDelegateMouse.containsMouse ? Qt.rgba(1, 1, 1, 0.16) : (userDelegateItem.isSelected ? Qt.rgba(1, 1, 1, 0.10) : "transparent") border.color: userDelegateItem.isSelected ? Qt.rgba(1, 1, 1, 0.45) : (userDelegateMouse.containsMouse ? Qt.rgba(1, 1, 1, 0.25) : "transparent") border.width: 1 Behavior on color { ColorAnimation { duration: 100 } } Behavior on border.color { ColorAnimation { duration: 100 } } } Row { anchors.fill: parent anchors.leftMargin: root.font.pointSize * 0.8 anchors.rightMargin: root.font.pointSize * 0.8 spacing: root.font.pointSize * 0.8 // Mini avatar in dropdown row Item { width: root.font.pointSize * 2.4 height: root.font.pointSize * 2.4 anchors.verticalCenter: parent.verticalCenter Rectangle { anchors.fill: parent radius: width / 2 clip: true color: Qt.rgba(1, 1, 1, 0.15) border.color: Qt.rgba(1, 1, 1, 0.35) border.width: 1 Item { id: dMask anchors.fill: parent visible: false layer.enabled: true Rectangle { anchors.fill: parent radius: parent.width / 2 color: "black" } } Image { id: dPhoto anchors.fill: parent fillMode: Image.PreserveAspectCrop smooth: true visible: status === Image.Ready layer.enabled: true layer.effect: MultiEffect { maskEnabled: true maskSource: dMask } onStatusChanged: { if (status === Image.Error) { userDelegateItem.tryNextItemCandidate() } } } Button { anchors.centerIn: parent width: parent.width * 0.65 height: parent.height * 0.65 enabled: false icon.source: Qt.resolvedUrl("../Assets/User.svg") icon.width: parent.width * 0.65 icon.height: parent.height * 0.65 icon.color: "#ffffff" visible: dPhoto.status !== Image.Ready background: Rectangle { color: "transparent" } } } } // Username & realName Column { anchors.verticalCenter: parent.verticalCenter spacing: 2 Text { text: model.name || "" color: "#ffffff" font.bold: true font.pointSize: root.font.pointSize * 0.85 font.family: root.font.family style: Text.Raised styleColor: Qt.rgba(0, 0, 0, 0.40) } Text { text: (model.realName && model.realName !== model.name) ? model.realName : "" color: Qt.rgba(1, 1, 1, 0.65) font.pointSize: root.font.pointSize * 0.70 font.family: root.font.family visible: text !== "" } } } MouseArea { id: userDelegateMouse anchors.fill: parent hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: { usernameField.selectUserAt(index) } } } } } } Item { id: passwordField height: root.font.pointSize * 3.8 width: parent.width anchors.horizontalCenter: parent.horizontalCenter Button { id: passwordIcon height: parent.height width: parent.height anchors.left: parent.left anchors.verticalCenter: parent.verticalCenter z: 2 icon.height: parent.height * 0.25 icon.width: parent.height * 0.25 icon.color: config.PasswordIconColor icon.source: Qt.resolvedUrl("../Assets/Password2.svg") background: Rectangle { color: "transparent" border.color: "transparent" } states: [ State { name: "visiblePasswordFocused" when: passwordIcon.checked && passwordIcon.activeFocus PropertyChanges { target: passwordIcon icon.source: Qt.resolvedUrl("../Assets/Password.svg") icon.color: config.HoverPasswordIconColor } }, State { name: "visiblePasswordHovered" when: passwordIcon.checked && passwordIcon.hovered PropertyChanges { target: passwordIcon icon.source: Qt.resolvedUrl("../Assets/Password.svg") icon.color: config.HoverPasswordIconColor } }, State { name: "visiblePassword" when: passwordIcon.checked PropertyChanges { target: passwordIcon icon.source: Qt.resolvedUrl("../Assets/Password.svg") } }, State { name: "hiddenPasswordFocused" when: passwordIcon.enabled && passwordIcon.activeFocus PropertyChanges { target: passwordIcon icon.source: Qt.resolvedUrl("../Assets/Password2.svg") icon.color: config.HoverPasswordIconColor } }, State { name: "hiddenPasswordHovered" when: passwordIcon.hovered PropertyChanges { target: passwordIcon icon.source: Qt.resolvedUrl("../Assets/Password2.svg") icon.color: config.HoverPasswordIconColor } } ] onClicked: toggle() Keys.onReturnPressed: toggle() Keys.onEnterPressed: toggle() KeyNavigation.down: password } TextField { id: password height: root.font.pointSize * 2.8 width: parent.width anchors.centerIn: parent horizontalAlignment: TextInput.AlignHCenter font.bold: true color: config.PasswordFieldTextColor focus: config.PasswordFocus == "true" ? true : false echoMode: passwordIcon.checked ? TextInput.Normal : TextInput.Password placeholderText: config.TranslatePlaceholderPassword || textConstants.password placeholderTextColor: config.PlaceholderTextColor passwordCharacter: "•" passwordMaskDelay: config.HideCompletePassword == "true" ? undefined : 1000 renderType: Text.QtRendering selectByMouse: true background: Item { Rectangle { anchors.fill: parent anchors.topMargin: root.font.pointSize * 0.12 radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 color: Qt.rgba(0, 0, 0, 0.20) } Rectangle { anchors.fill: parent color: password.activeFocus ? Qt.rgba(1, 1, 1, 0.25) : Qt.rgba(1, 1, 1, 0.14) border.color: password.activeFocus ? Qt.rgba(255, 255, 255, 0.65) : Qt.rgba(255, 255, 255, 0.25) border.width: password.activeFocus ? root.font.pointSize * 0.12 : root.font.pointSize * 0.08 radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 Behavior on color { ColorAnimation { duration: 150 } } Behavior on border.color { ColorAnimation { duration: 150 } } } } onAccepted: config.AllowUppercaseLettersInUsernames == "false" ? sddm.login(username.text.toLowerCase(), password.text, sessionSelect.selectedSession) : sddm.login(username.text, password.text, sessionSelect.selectedSession) KeyNavigation.down: loginButton } states: [ State { name: "focused" when: password.activeFocus PropertyChanges { target: password color: Qt.lighter(config.LoginFieldTextColor, 1.15) } } ] transitions: [ Transition { PropertyAnimation { properties: "color, border.color" duration: 150 } } ] } Item { id: login height: root.font.pointSize * 4.2 width: parent.width anchors.horizontalCenter: parent.horizontalCenter visible: config.HideLoginButton == "true" ? false : true Item { id: loginButton height: root.font.pointSize * 2.8 width: parent.width anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter focus: true activeFocusOnTab: true property bool hovered: hoverArea.containsMouse property bool down: hoverArea.pressed signal clicked() onClicked: config.AllowUppercaseLettersInUsernames == "false" ? sddm.login(username.text.toLowerCase(), password.text, sessionSelect.selectedSession) : sddm.login(username.text, password.text, sessionSelect.selectedSession) Keys.onReturnPressed: clicked() Keys.onEnterPressed: clicked() KeyNavigation.down: rebootBtn // Drop shadow Rectangle { anchors.fill: parent anchors.topMargin: root.font.pointSize * 0.12 radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 color: Qt.rgba(0, 0, 0, 0.25) } Rectangle { id: buttonBackground anchors.fill: parent radius: config.RoundCorners !== "" ? parseInt(config.RoundCorners) : root.font.pointSize * 0.8 border.width: loginButton.activeFocus ? root.font.pointSize * 0.12 : root.font.pointSize * 0.08 border.color: loginButton.down ? Qt.rgba(21/255, 128/255, 61/255, 0.95) : (loginButton.hovered ? Qt.rgba(34/255, 197/255, 94/255, 0.85) : Qt.rgba(74/255, 222/255, 128/255, 0.65)) color: loginButton.down ? Qt.rgba(21/255, 128/255, 61/255, 0.80) : (loginButton.hovered ? Qt.rgba(34/255, 197/255, 94/255, 0.65) : Qt.rgba(74/255, 222/255, 128/255, 0.40)) Behavior on border.color { ColorAnimation { duration: 150 } } Behavior on color { ColorAnimation { duration: 150 } } } Text { id: loginButtonText anchors.centerIn: parent font.bold: true font.pointSize: root.font.pointSize font.family: root.font.family color: "#ffffff" style: Text.Raised styleColor: Qt.rgba(0, 0, 0, 0.45) text: config.TranslateLogin || textConstants.login opacity: 1.0 Behavior on opacity { NumberAnimation { duration: 150 } } } MouseArea { id: hoverArea anchors.fill: parent hoverEnabled: true onClicked: parent.clicked() } } } Item { id: powerButtonsRow height: root.font.pointSize * 5.5 width: parent.width anchors.horizontalCenter: parent.horizontalCenter Row { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter spacing: root.font.pointSize * 1.5 // Reboot gomb Column { spacing: root.font.pointSize * 0.45 Item { width: root.font.pointSize * 4.2 height: root.font.pointSize * 4.2 // Button shadow Rectangle { anchors.fill: parent anchors.topMargin: root.font.pointSize * 0.12 radius: width / 2 color: Qt.rgba(0, 0, 0, 0.30) } RoundButton { id: rebootBtn anchors.fill: parent activeFocusOnTab: true Keys.onReturnPressed: sddm.reboot() Keys.onEnterPressed: sddm.reboot() KeyNavigation.right: shutdownBtn hoverEnabled: true icon.source: Qt.resolvedUrl("../Assets/Reboot.svg") icon.width: root.font.pointSize * 2.1 icon.height: root.font.pointSize * 2.1 icon.color: "#ffffff" opacity: rebootBtn.hovered || rebootBtn.activeFocus ? 1.0 : 0.75 Behavior on opacity { NumberAnimation { duration: 150 } } scale: rebootBtn.pressed ? 0.88 : 1.0 Behavior on scale { NumberAnimation { duration: 100 } } background: Rectangle { anchors.fill: parent radius: width / 2 color: rebootBtn.pressed ? Qt.rgba(1, 0.45, 0.0, 0.35) : (rebootBtn.hovered ? Qt.rgba(1, 0.55, 0.0, 0.22) : "transparent") border.color: "transparent" border.width: 0 Behavior on color { ColorAnimation { duration: 150 } } } onClicked: sddm.reboot() } } Text { anchors.horizontalCenter: parent.children[0].horizontalCenter text: config.TranslateReboot || textConstants.reboot color: "#ffffff" style: Text.Raised styleColor: Qt.rgba(0, 0, 0, 0.50) font.pointSize: root.font.pointSize * 0.8 font.family: root.font.family horizontalAlignment: Text.AlignHCenter opacity: rebootBtn.hovered || rebootBtn.activeFocus ? 1.0 : 0.75 Behavior on opacity { NumberAnimation { duration: 150 } } } } // Shutdown gomb Column { spacing: root.font.pointSize * 0.45 Item { width: root.font.pointSize * 4.2 height: root.font.pointSize * 4.2 // Button shadow Rectangle { anchors.fill: parent anchors.topMargin: root.font.pointSize * 0.12 radius: width / 2 color: Qt.rgba(0, 0, 0, 0.30) } RoundButton { id: shutdownBtn anchors.fill: parent activeFocusOnTab: true Keys.onReturnPressed: sddm.powerOff() Keys.onEnterPressed: sddm.powerOff() KeyNavigation.left: rebootBtn hoverEnabled: true icon.source: Qt.resolvedUrl("../Assets/Shutdown.svg") icon.width: root.font.pointSize * 2.1 icon.height: root.font.pointSize * 2.1 icon.color: "#ffffff" opacity: shutdownBtn.hovered || shutdownBtn.activeFocus ? 1.0 : 0.75 Behavior on opacity { NumberAnimation { duration: 150 } } scale: shutdownBtn.pressed ? 0.88 : 1.0 Behavior on scale { NumberAnimation { duration: 100 } } background: Rectangle { anchors.fill: parent radius: width / 2 color: shutdownBtn.pressed ? Qt.rgba(0.8, 0.1, 0.1, 0.40) : (shutdownBtn.hovered ? Qt.rgba(0.8, 0.1, 0.1, 0.25) : "transparent") border.color: "transparent" border.width: 0 Behavior on color { ColorAnimation { duration: 150 } } } onClicked: sddm.powerOff() } } Text { anchors.horizontalCenter: parent.children[0].horizontalCenter text: config.TranslateShutdown || textConstants.shutdown color: "#ffffff" style: Text.Raised styleColor: Qt.rgba(0, 0, 0, 0.50) font.pointSize: root.font.pointSize * 0.8 font.family: root.font.family horizontalAlignment: Text.AlignHCenter opacity: shutdownBtn.hovered || shutdownBtn.activeFocus ? 1.0 : 0.75 Behavior on opacity { NumberAnimation { duration: 150 } } } } } } Connections { target: sddm function onLoginSucceeded() { } function onLoginFailed() { failed = true; resetError.running ? resetError.stop() && resetError.start() : resetError.start(); } } Timer { id: resetError interval: 2000 onTriggered: failed = false running: false } }