diff --git a/lookandfeel/contents/components/UserDelegate.qml b/lookandfeel/contents/components/UserDelegate.qml index c19f92fb1..b74e657ce 100644 --- a/lookandfeel/contents/components/UserDelegate.qml +++ b/lookandfeel/contents/components/UserDelegate.qml @@ -1,156 +1,157 @@ /* * Copyright 2014 David Edmundson * Copyright 2014 Aleix Pol Gonzalez * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.4 import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents Item { id: wrapper property bool isCurrent: true property string name property string userName property string avatarPath property string iconSource + property bool constrainText: true signal clicked() property real faceSize: Math.min(width, height - usernameDelegate.height - units.largeSpacing) opacity: isCurrent ? 1.0 : 0.5 Behavior on opacity { OpacityAnimator { duration: units.longDuration } } Item { id: imageSource width: faceSize height: faceSize //Image takes priority, taking a full path to a file, if that doesn't exist we show an icon Image { id: face source: wrapper.avatarPath sourceSize: Qt.size(faceSize, faceSize) fillMode: Image.PreserveAspectCrop anchors.fill: parent } PlasmaCore.IconItem { id: faceIcon source: iconSource visible: (face.status == Image.Error || face.status == Image.Null) anchors.fill: parent anchors.margins: units.gridUnit * 0.5 // because mockup says so... colorGroup: PlasmaCore.ColorScope.colorGroup } } ShaderEffect { anchors.top: parent.top anchors.horizontalCenter: parent.horizontalCenter width: imageSource.width height: imageSource.height supportsAtlasTextures: true property var source: ShaderEffectSource { sourceItem: imageSource hideSource: true live: false } property var colorBorder: PlasmaCore.ColorScope.textColor //draw a circle with an antialised border //innerRadius = size of the inner circle with contents //outerRadius = size of the border //blend = area to blend between two colours //all sizes are normalised so 0.5 == half the width of the texture //if copying into another project don't forget to connect themeChanged to update() //but in SDDM that's a bit pointless fragmentShader: " varying highp vec2 qt_TexCoord0; uniform highp float qt_Opacity; uniform lowp sampler2D source; uniform vec4 colorBorder; float blend = 0.01; float innerRadius = 0.47; float outerRadius = innerRadius + 0.02; vec4 colorEmpty = vec4(0.0, 0.0, 0.0, 0.0); void main() { vec4 colorSource = texture2D(source, qt_TexCoord0.st); vec2 m = qt_TexCoord0 - vec2(0.5, 0.5); float dist = sqrt(m.x * m.x + m.y * m.y); if (dist < innerRadius) gl_FragColor = colorSource; else if (dist < innerRadius + blend) gl_FragColor = mix(colorSource, colorBorder, ((dist - innerRadius) / blend)); else if (dist < outerRadius) gl_FragColor = colorBorder; else if (dist < outerRadius + blend) gl_FragColor = mix(colorBorder, colorEmpty, ((dist - outerRadius) / blend)); else gl_FragColor = colorEmpty ; gl_FragColor = gl_FragColor * qt_Opacity; } " } PlasmaComponents.Label { id: usernameDelegate anchors { bottom: parent.bottom - left: parent.left - right: parent.right + horizontalCenter: parent.horizontalCenter } height: implicitHeight // work around stupid bug in Plasma Components that sets the height + width: constrainText ? parent.width : implicitWidth text: wrapper.name elide: Text.ElideRight horizontalAlignment: Text.AlignHCenter //make an indication that this has active focus, this only happens when reached with keyboard navigation font.underline: wrapper.activeFocus } MouseArea { anchors.fill: parent hoverEnabled: true onClicked: wrapper.clicked(); } Accessible.name: name Accessible.role: Accessible.Button function accessiblePressAction() { wrapper.clicked() } } diff --git a/lookandfeel/contents/components/UserList.qml b/lookandfeel/contents/components/UserList.qml index e4a863101..a2d85088f 100644 --- a/lookandfeel/contents/components/UserList.qml +++ b/lookandfeel/contents/components/UserList.qml @@ -1,90 +1,93 @@ /* * Copyright 2014 David Edmundson * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 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 Library General Public * License along with this program; if not, write to the * Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import QtQuick 2.2 ListView { id: view readonly property string selectedUser: currentItem ? currentItem.userName : "" readonly property int userItemWidth: units.gridUnit * 8 readonly property int userItemHeight: units.gridUnit * 8 implicitHeight: userItemHeight activeFocusOnTab : true /* * Signals that a user was explicitly selected */ signal userSelected; orientation: ListView.Horizontal highlightRangeMode: ListView.StrictlyEnforceRange //centre align selected item (which implicitly centre aligns the rest preferredHighlightBegin: width/2 - userItemWidth/2 preferredHighlightEnd: preferredHighlightBegin delegate: UserDelegate { avatarPath: model.icon || "" iconSource: model.iconName || "user-identity" name: { var displayName = model.realName || model.name if (model.vtNumber === undefined || model.vtNumber < 0) { return displayName } if (!model.session) { return i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Nobody logged in on that session", "Unused") } var location = "" if (model.isTty) { location = i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "User logged in on console number", "TTY %1", model.vtNumber) } else if (model.displayNumber) { location = i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "User logged in on console (X display number)", "on TTY %1 (Display %2)", model.vtNumber, model.displayNumber) } if (location) { return i18ndc("plasma_lookandfeel_org.kde.lookandfeel", "Username (location)", "%1 (%2)", displayName, location) } return displayName } userName: model.name width: userItemWidth height: userItemHeight + //if we only have one delegate, we don't need to clip the text as it won't be overlapping with anything + constrainText: ListView.view.count > 1 + isCurrent: ListView.isCurrentItem onClicked: { ListView.view.currentIndex = index; ListView.view.userSelected(); } } Keys.onEscapePressed: view.userSelected() Keys.onEnterPressed: view.userSelected() Keys.onReturnPressed: view.userSelected() } diff --git a/lookandfeel/contents/logout/Logout.qml b/lookandfeel/contents/logout/Logout.qml index 251e1ee1f..180dd5ae2 100644 --- a/lookandfeel/contents/logout/Logout.qml +++ b/lookandfeel/contents/logout/Logout.qml @@ -1,230 +1,231 @@ /*************************************************************************** * Copyright (C) 2014 by Aleix Pol Gonzalez * * * * 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, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA . * ***************************************************************************/ import QtQuick 2.2 import QtQuick.Layouts 1.2 import QtQuick.Controls 1.1 as Controls import org.kde.plasma.core 2.0 as PlasmaCore import org.kde.plasma.components 2.0 as PlasmaComponents import org.kde.kcoreaddons 1.0 as KCoreAddons import "../components" PlasmaCore.ColorScope { id: root colorGroup: PlasmaCore.Theme.ComplementaryColorGroup height: screenGeometry.height width: screenGeometry.width signal logoutRequested() signal haltRequested() signal suspendRequested(int spdMethod) signal rebootRequested() signal rebootRequested2(int opt) signal cancelRequested() signal lockScreenRequested() property alias backgroundColor: backgroundRect.color function sleepRequested() { root.suspendRequested(2); } property real timeout: 30 property real remainingTime: root.timeout property var currentAction: { switch (sdtype) { case ShutdownType.ShutdownTypeReboot: return root.rebootRequested; case ShutdownType.ShutdownTypeHalt: return root.haltRequested; default: return root.logoutRequested; } } KCoreAddons.KUser { id: kuser } Controls.Action { onTriggered: root.cancelRequested() shortcut: "Escape" } onRemainingTimeChanged: { if (remainingTime <= 0) { root.currentAction(); } } Timer { id: countDownTimer running: true repeat: true interval: 1000 onTriggered: remainingTime-- } function rgbToHsv(color) { var max = Math.max(color.r, color.g, color.b); var min = Math.min(color.r, color.g, color.b); var d = max - min; var h; var s = (max === 0 ? 0 : d / max); var v = max / 255; switch (max) { case min: h = 0; break; case color.r: h = (color.g - color.b) + d * (color.g < color.b ? 6: 0); h /= 6 * d; break; case color.g: h = (color.b - color.r) + d * 2; h /= 6 * d; break; case color.b: h = (color.r - color.g) + d * 4; h /= 6 * d; break; } return { h: h, s: s, v: v }; } Rectangle { id: backgroundRect anchors.fill: parent //use "black" because this is intended to look like a general darkening of the scene. a dark gray as normal background would just look too "washed out" color: root.rgbToHsv(PlasmaCore.ColorScope.backgroundColor).v > 128 ? PlasmaCore.ColorScope.backgroundColor : "black" opacity: 0.5 } MouseArea { anchors.fill: parent onClicked: root.cancelRequested() } UserDelegate { width: units.iconSizes.enormous height: width anchors { horizontalCenter: parent.horizontalCenter bottom: parent.verticalCenter } + constrainText: false avatarPath: kuser.faceIconUrl iconSource: "user-identity" isCurrent: true name: kuser.fullName } ColumnLayout { anchors { top: parent.verticalCenter topMargin: units.gridUnit * 2 horizontalCenter: parent.horizontalCenter } spacing: units.largeSpacing height: Math.max(implicitHeight, units.gridUnit * 10) width: Math.max(implicitWidth, units.gridUnit * 16) RowLayout { spacing: units.largeSpacing * 2 Layout.alignment: Qt.AlignHCenter LogoutButton { id: suspendButton iconSource: "system-suspend" text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Suspend") action: root.sleepRequested KeyNavigation.left: logoutButton KeyNavigation.right: rebootButton visible: spdMethods.SuspendState } LogoutButton { id: rebootButton iconSource: "system-reboot" text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Reboot") action: root.rebootRequested KeyNavigation.left: suspendButton KeyNavigation.right: shutdownButton focus: sdtype == ShutdownType.ShutdownTypeReboot visible: maysd } LogoutButton { id: shutdownButton iconSource: "system-shutdown" text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shutdown") action: root.haltRequested KeyNavigation.left: rebootButton KeyNavigation.right: logoutButton focus: sdtype == ShutdownType.ShutdownTypeHalt visible: maysd } LogoutButton { id: logoutButton iconSource: "system-log-out" text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Logout") action: root.logoutRequested KeyNavigation.left: shutdownButton KeyNavigation.right: suspendButton focus: sdtype == ShutdownType.ShutdownTypeNone visible: canLogout } } PlasmaComponents.Label { Layout.alignment: Qt.AlignHCenter //opacity, as visible would re-layout opacity: countDownTimer.running ? 1 : 0 Behavior on opacity { OpacityAnimator { duration: units.longDuration easing.type: Easing.InOutQuad } } text: { switch (sdtype) { case ShutdownType.ShutdownTypeReboot: return i18ndp("plasma_lookandfeel_org.kde.lookandfeel", "Reboot in 1 second", "Reboot in %1 seconds", root.remainingTime); case ShutdownType.ShutdownTypeHalt: return i18ndp("plasma_lookandfeel_org.kde.lookandfeel", "Shutting down in 1 second", "Shutting down in %1 seconds", root.remainingTime); default: return i18ndp("plasma_lookandfeel_org.kde.lookandfeel", "Logging out in 1 second", "Logging out in %1 seconds", root.remainingTime); } } } RowLayout { Layout.alignment: Qt.AlignHCenter PlasmaComponents.Button { enabled: root.currentAction != null text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "OK") onClicked: root.currentAction() } PlasmaComponents.Button { text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Cancel") onClicked: root.cancelRequested() } } } }