/* * SPDX-FileCopyrightText: zayronxio * SPDX-License-Identifier: GPL-3.0-or-later */ import QtQuick import QtQuick.Layouts import org.kde.plasma.plasmoid import org.kde.plasma.core as PlasmaCore import org.kde.plasma.components as PlasmaComponents3 import org.kde.plasma.extras as PlasmaExtras import org.kde.plasma.private.kicker as Kicker import org.kde.coreaddons as KCoreAddons // kuser //import org.kde.plasma.private.shell import org.kde.plasma.private.sessions as Sessions import org.kde.kwindowsystem import org.kde.kquickcontrolsaddons import org.kde.plasma.private.quicklaunch import QtQuick.Controls import org.kde.kirigami as Kirigami import org.kde.ksvg as KSvg import org.kde.plasma.plasma5support as P5Support import org.kde.kcmutils as KCM import Qt5Compat.GraphicalEffects Item { id: main property var locale: Qt.locale() property int sizeImage: Kirigami.Units.iconSizes.large * 2 property int menuPos: 0 property int showApps: Plasmoid.configuration.viewUser ? 0 : 1 onVisibleChanged: { root.visible = !root.visible } PlasmaExtras.Menu { id: contextMenu PlasmaExtras.MenuItem { action: Plasmoid.internalAction("configure") } } Plasmoid.status: root.visible ? PlasmaCore.Types.RequiresAttentionStatus : PlasmaCore.Types.PassiveStatus PlasmaCore.Dialog { id: root objectName: "popupWindow" flags: Qt.WindowStaysOnTopHint //flags: Qt.Dialog | Qt.FramelessWindowHint location: PlasmaCore.Types.Floating hideOnWindowDeactivate: true property int iconSize: Kirigami.Units.iconSizes.large property int cellSizeHeight: iconSize + Kirigami.Units.gridUnit * 2 + (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom, highlightItemSvg.margins.left + highlightItemSvg.margins.right)) property int cellSizeWidth: cellSizeHeight property bool searching: (searchField.text != "") property bool showFavorites onVisibleChanged: { if (visible) { root.showFavorites = Plasmoid.configuration.showFavoritesFirst var pos = popupPosition(width, height); x = pos.x; y = pos.y; reset(); animation1.start() }else{ rootItem.opacity = 0 } } onHeightChanged: { var pos = popupPosition(width, height); x = pos.x; y = pos.y; } onWidthChanged: { var pos = popupPosition(width, height); x = pos.x; y = pos.y; } function toggle(){ main.visible = !main.visible } function reset() { searchField.text = ""; if(showFavorites) globalFavoritesGrid.tryActivate(0,0) else mainColumn.visibleGrid.tryActivate(0,0) } function popupPosition(width, height) { var screenAvail = kicker.availableScreenRect; var screen = kicker.screenGeometry; var panelH = kicker.height var panelW = kicker.width var horizMidPoint = screen.x + (screen.width / 2); var vertMidPoint = screen.y + (screen.height / 2); var appletTopLeft = parent.mapToGlobal(0, 0); var offset = Kirigami.Units.smallSpacing * 2; if (Plasmoid.configuration.displayPosition === 1) { horizMidPoint = screen.x + (screen.width / 2); vertMidPoint = screen.y + (screen.height / 2); x = horizMidPoint - width / 2; y = vertMidPoint - height / 2; } else if (Plasmoid.configuration.displayPosition === 2) { horizMidPoint = screen.x + (screen.width / 2); vertMidPoint = screen.y + (screen.height / 2); x = horizMidPoint - width / 2; // y = screen.y + screen.height - height - offset - panelH - Kirigami.Units.gridUnit; // y = screen.y + screen.height - height - offset - panelH - Kirigami.Units.gridUnit / 2; y = screen.y + screen.height - height - offset - panelH - Kirigami.Units.largeSpacing * 1.5; } else { switch (plasmoid.location) { case PlasmaCore.Types.BottomEdge: var y = appletTopLeft.y - height - offset var x = appletTopLeft.x break; case PlasmaCore.Types.TopEdge: x = appletTopLeft.x < screen.width - width ? appletTopLeft.x + panelW - Kirigami.Units.gridUnit / 3 : screen.width - width; y = appletTopLeft.y + kicker.height + Kirigami.Units.gridUnit break; case PlasmaCore.Types.LeftEdge: x = appletTopLeft.x + panelW + Kirigami.Units.gridUnit / 2; y = appletTopLeft.y < screen.height - height ? appletTopLeft.y : appletTopLeft.y - height + iconUser.height / 2; break; case PlasmaCore.Types.RightEdge: x = appletTopLeft.x - width - Kirigami.Units.gridUnit / 2; y = appletTopLeft.y < screen.height - height ? appletTopLeft.y : screen.height - height - Kirigami.Units.gridUnit / 5; break; default: return; } } return Qt.point(x, y); } FocusScope { id: rootItem Layout.minimumWidth: Kirigami.Units.gridUnit*30 Layout.maximumWidth: minimumWidth Layout.minimumHeight: (root.cellSizeHeight * Plasmoid.configuration.numberRows) + searchField.implicitHeight + (Plasmoid.configuration.viewUser ? main.sizeImage*0.5 : Kirigami.Units.gridUnit * 1.5 ) + Kirigami.Units.gridUnit * 5 Layout.maximumHeight: (root.cellSizeHeight * Plasmoid.configuration.numberRows) + searchField.implicitHeight + (Plasmoid.configuration.viewUser ? main.sizeImage*0.5 : Kirigami.Units.gridUnit * 1.5 ) + Kirigami.Units.gridUnit * 5 focus: true Sessions.SessionManagement { id: sm } Sessions.SessionsModel { id: sessionsModel } KCoreAddons.KUser { id: kuser } Logic { id: logic } OpacityAnimator { id: animation1; target: rootItem; from: 0; to: 1; easing.type: Easing.InOutQuad; } P5Support.DataSource { id: executable engine: "executable" connectedSources: [] onNewData: { var exitCode = data["exit code"] var exitStatus = data["exit status"] var stdout = data["stdout"] var stderr = data["stderr"] exited(sourceName, exitCode, exitStatus, stdout, stderr) disconnectSource(sourceName) } function exec(cmd) { if (cmd) { connectSource(cmd) } } signal exited(string cmd, int exitCode, int exitStatus, string stdout, string stderr) } PlasmaExtras.Highlight { id: delegateHighlight visible: false z: -1 // otherwise it shows ontop of the icon/label and tints them slightly } Kirigami.Heading { id: dummyHeading visible: false width: 0 level: 5 } TextMetrics { id: headingMetrics font: dummyHeading.font } Item { id : headingSvg width: parent.height + backgroundSvg.margins.bottom + backgroundSvg.margins.top //height: root.cellSizeHeight * Plasmoid.configuration.numberRows + Kirigami.Units.gridUnit * 2 + backgroundSvg.margins.bottom - 1 //<>+ paginationBar.height height: parent.width*.4 + backgroundSvg.margins.left } RowLayout { id: rowSearchField width: parent.width*.4 anchors{ top: parent.top topMargin: Kirigami.Units.gridUnit*1 left: parent.left leftMargin: (parent.width*.6 - width)/2 margins: Kirigami.Units.smallSpacing } PlasmaComponents3.TextField { id: searchField Layout.fillWidth: true placeholderText: i18n("Type here to search ...") topPadding: 10 bottomPadding: 10 leftPadding: ((parent.width - width)/2) + Kirigami.Units.iconSizes.small*2 text: "" font.pointSize: Kirigami.Theme.defaultFont.pointSize onTextChanged: { runnerModel.query = text; } Keys.onPressed: (event)=> { if (event.key === Qt.Key_Escape) { event.accepted = true; if(root.searching){ searchField.clear() } else { root.toggle() } } if (event.key === Qt.Key_Down || event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab) { event.accepted = true; if(root.showFavorites) globalFavoritesGrid.tryActivate(0,0) else mainColumn.visibleGrid.tryActivate(0,0) } } function backspace() { if (!root.visible) { return; } focus = true; text = text.slice(0, -1); } function appendText(newText) { if (!root.visible) { return; } focus = true; text = text + newText; } Kirigami.Icon { source: 'search' anchors { left: searchField.left verticalCenter: searchField.verticalCenter leftMargin: Kirigami.Units.smallSpacing * 2 } height: Kirigami.Units.iconSizes.small width: height } } Item { Layout.fillWidth: true } } Item { id: selectorAppsFavsOrAll width: (parent.width - places.width)*.85 height: 30 anchors.left: parent.left anchors.leftMargin: 15 anchors.bottom: parent.bottom anchors.bottomMargin: Kirigami.Units.gridUnit*1.5 Row { height: parent.height width: parent.width Rectangle { id: baseIcon color: Kirigami.Theme.textColor opacity: 0.35 height: 24 width: height radius: height/2 anchors.verticalCenter: parent.verticalCenter Row { width: parent.width*.8 height: 24 spacing: height/6 anchors.horizontalCenter: parent.horizontalCenter Repeater { model: ListModel { ListElement { name: "one" } ListElement { name: "two" } ListElement { name: "three" } } Rectangle { color: Kirigami.Theme.textColor width: parent.width/5 height: width radius: height/2 anchors.verticalCenter: parent.verticalCenter } } } MouseArea { width: parent.width height: parent.height anchors.centerIn: baseIcon onClicked: { var apps = showApps showApps = apps === 0 ? 1 : 0 } } } Text { height: selectorAppsFavsOrAll.height text: showApps === 0 ? i18n("All apps") : i18n("Favorites") font.pixelSize: 12 anchors.left: parent.left anchors.leftMargin: baseIcon.width*1.5 color: Kirigami.Theme.textColor verticalAlignment: Text.AlignVCenter MouseArea { width: parent.width height: parent.height anchors.centerIn: parent onClicked: { var apps = showApps showApps = apps === 0 ? 1 : 0 } } } Kirigami.Icon { id: arrow source: showApps === 1 ? "arrow-left" : "arrow-right" width: 22 height: 22 anchors.right: parent.right anchors.rightMargin: width MouseArea { width: parent.width height: parent.height anchors.centerIn: parent onClicked: { var apps = showApps showApps = apps === 0 ? 1 : 0 } } } } } ItemGridView { id: globalFavoritesGrid visible: showApps === 0 anchors { top: rowSearchField.bottom topMargin: Kirigami.Units.gridUnit * 2 } dragEnabled: true dropEnabled: true width: rootItem.width*.6 height: root.cellSizeHeight * Plasmoid.configuration.numberRows focus: true cellWidth: root.width*.6 cellHeight: 48 iconSize: 32 onKeyNavUp: searchField.focus = true Keys.onPressed:(event)=> { if(event.modifiers & Qt.ControlModifier ||event.modifiers & Qt.ShiftModifier){ searchField.focus = true; return } if (event.key === Qt.Key_Tab) { event.accepted = true; searchField.focus = true } } } PlasmaCore.Dialog { id: dialog width: main.sizeImage*.85 height: width visible: root.visible y: root.y + sizeImage/3 x: root.x + root.width*.68 objectName: "popupWindowIcon" //flags: Qt.WindowStaysOnTopHint type: "Notification" location: PlasmaCore.Types.Floating hideOnWindowDeactivate: false backgroundHints: PlasmaCore.Dialog.NoBackground mainItem: Rectangle { width: main.sizeImage*.7 height: width color: 'transparent' Rectangle { id: mask width: parent.width height: parent.height visible: false radius: height/2 } Image { id: iconUser source: kuser.faceIconUrl cache: false visible: source !== "" && Plasmoid.configuration.viewUser width: parent.width height: parent.height fillMode: Image.PreserveAspectFit layer.enabled:true state: "hide" states: [ State { name: "show" when: dialog.visible PropertyChanges { target: iconUser; y: 0; opacity: 1; } }, State { name: "hide" when: !dialog.visible PropertyChanges { target: iconUser; y: sizeImage/3 ; opacity: 0; } } ] transitions: Transition { PropertyAnimation { properties: "opacity,y"; easing.type: Easing.InOutQuad; } } layer.effect: OpacityMask { maskSource: mask } MouseArea { anchors.fill: parent acceptedButtons: Qt.LeftButton hoverEnabled: true cursorShape: Qt.PointingHandCursor onClicked: KCM.KCMLauncher.openSystemSettings("kcm_users") } } } } Column { id: greetingUser width: headingSvg.height*.8 height: 20 anchors.right: parent.right anchors.top: parent.top anchors.topMargin: dialog.height + Kirigami.Units.largeSpacing * 2 Item { width: textuser.implicitWidth height: textuser.implicitHeight visible: true anchors.top: parent.top anchors.left: parent.left Text { width: parent.width height: 20 id: textuser text: i18n("Hi, ")+ kuser.fullName font.bold: true font.pixelSize: 16 color: Kirigami.Theme.textColor } } } Column { id: places width: headingSvg.height*.8 height: parent.height - dialog.height / 2 - Kirigami.Units.gridUnit * 5.5 anchors.right: parent.right anchors.bottom: parent.bottom ListModel { id: placeModel ListElement { type: "place" label: "Home" icon: "user-home-symbolic" command: "xdg-open $HOME" } ListElement { type: "place" label: "Downloads" icon: "folder-downloads-symbolic" command: "xdg-open $(xdg-user-dir DOWNLOAD)" } ListElement { type: "place" label: "Documents" icon: "folder-documents-symbolic" command: "xdg-open $(xdg-user-dir DOCUMENTS)" } ListElement { type: "place" label: "Music" icon: "folder-music-symbolic" command: "xdg-open $(xdg-user-dir MUSIC)" } ListElement { type: "place" label: "Pictures" icon: "folder-pictures-symbolic" command: "xdg-open $(xdg-user-dir PICTURES)" } ListElement { type: "place" label: "Videos" icon: "folder-videos-symbolic" command: "xdg-open $(xdg-user-dir VIDEOS)" } ListElement { type: "separator" label: "" icon: "" command: "" } ListElement { type: "shortcut" label: "System Preferences" icon: "systemsettings" command: "xdg-open systemsettings://" } ListElement { type: "shortcut" label: "Personalization" icon: "preferences-desktop-theme-global" command: "xdg-open systemsettings://kcm_colors" } ListElement { type: "shortcut" label: "Devices and Printers" icon: "preferences-devices-printer" command: "xdg-open systemsettings://kcm_printer_manager" } ListElement { type: "shortcut" label: "Update Software" icon: "software-updates-updates" command: "plasma-discover --mode update" } ListElement { type: "shortcut" label: "Help and Support" icon: "system-help" command: "xdg-open https://discuss.kde.org/?source=vinyl-launcher" } } Component { id: placeDelegate Item { property double lineSpacing: 2.0 property double textLineSpacing: 1.9 height: Kirigami.Units.iconSizes.small * lineSpacing width: parent.width Column { Row { Text { property var i18nDomain: (type === "place") ? "xdg-user-dirs" : "plasma_applet_DeepinMenu.Classic" verticalAlignment: Text.AlignVCenter height: Kirigami.Units.iconSizes.small * textLineSpacing leftPadding: Kirigami.Units.iconSizes.small * textLineSpacing + Kirigami.Units.largeSpacing font.pointSize: Kirigami.Theme.defaultFont.pointSize color: Kirigami.Theme.textColor text: (label !== "") ? i18nd(i18nDomain, label) : model.label Kirigami.Icon { source: model.icon height: Kirigami.Units.iconSizes.small * textLineSpacing width: Kirigami.Units.iconSizes.small * textLineSpacing color: Kirigami.Theme.textColor } MouseArea { width: parent.width height: parent.height anchors.centerIn: parent cursorShape: Qt.PointingHandCursor onClicked: { executable.exec(command); } } } } } } } Component { id: lineSeparator Rectangle { width: parent.width height: Kirigami.Units.iconSizes.small * 3 color: "transparent" KSvg.SvgItem { anchors.verticalCenter: parent.verticalCenter imagePath: "widgets/line" elementId: "horizontal-line" width: parent.width height: 1 } } } Column { width: parent.width height: parent.height ListView { id: placesView width: parent.width height: parent.height model: placeModel delegate: placeDelegate } } } RowLayout { id: shutdownIcons spacing: Kirigami.Units.largeSpacing anchors.bottom: parent.bottom anchors.bottomMargin: Kirigami.Units.largeSpacing * 4 anchors.right: parent.right anchors.rightMargin: parent.width*.2 - width/2 // PlasmaComponents3.ToolButton { // icon.name: "configure" // onClicked: logic.openUrl("file:///usr/share/applications/systemsettings.desktop") // ToolTip.delay: 1000 // ToolTip.timeout: 1000 // ToolTip.visible: hovered // ToolTip.text: i18n("System Preferences") // } PlasmaComponents3.ToolButton { height: Kirigami.Units.iconSizes.small * 1.5 icon.name: "system-lock-screen-symbolic" //onClicked: pmEngine.performOperation("lockScreen") //enabled: pmEngine.data["Sleep States"]["LockScreen"] onClicked: sm.lock() ToolTip.delay: 200 ToolTip.timeout: 1000 ToolTip.visible: hovered ToolTip.text: i18n("Lock Screen") } PlasmaComponents3.ToolButton { height: Kirigami.Units.iconSizes.small * 1.5 icon.name: "system-switch-user-symbolic" onClicked: sm.switchUser() ToolTip.delay: 200 ToolTip.timeout: 1000 ToolTip.visible: hovered ToolTip.text: i18n("Switch User") } PlasmaComponents3.ToolButton { height: Kirigami.Units.iconSizes.small * 1.5 icon.name: "system-shutdown-symbolic" // onClicked: sm.requestShutdown() onClicked: sm.requestLogoutPrompt() ToolTip.delay: 200 ToolTip.timeout: 1000 ToolTip.visible: hovered ToolTip.text: i18n("Shutdown") } } Item { id: mainGrids visible: !globalFavoritesGrid.visible anchors { top: rowSearchField.bottom topMargin: Kirigami.Units.gridUnit * 2 //left: parent.left //right: parent.right } width: rootItem.width height: root.cellSizeHeight * Plasmoid.configuration.numberRows Item { id: mainColumn //width: root.cellSize * Plasmoid.configuration.numberColumns + Kirigami.Units.gridUnit width: rootItem.width height: root.cellSizeHeight * Plasmoid.configuration.numberRows property Item visibleGrid: allAppsGrid function tryActivate(row, col) { if (visibleGrid) { visibleGrid.tryActivate(row, col); } } ItemGridView { id: allAppsGrid //width: root.cellSize * Plasmoid.configuration.numberColumns + Kirigami.Units.gridUnit width: rootItem.width*.6 Layout.maximumWidth: rootItem.width*.6 height: root.cellSizeHeight * Plasmoid.configuration.numberRows cellWidth: root.width*.6 cellHeight: 48 iconSize: 32 enabled: (opacity == 1) ? 1 : 0 z: enabled ? 5 : -1 dropEnabled: false dragEnabled: false opacity: root.searching ? 0 : 1 onOpacityChanged: { if (opacity == 1) { //allAppsGrid.scrollBar.flickableItem.contentY = 0; mainColumn.visibleGrid = allAppsGrid; } } onKeyNavUp: searchField.focus = true } ItemMultiGridView { id: runnerGrid width: rootItem.width*.6 height: root.cellSizeHeight * Plasmoid.configuration.numberRows cellWidth: root.width*.6 cellHeight: 48 enabled: (opacity == 1.0) ? 1 : 0 z: enabled ? 5 : -1 model: runnerModel grabFocus: true opacity: root.searching ? 1.0 : 0.0 onOpacityChanged: { if (opacity == 1.0) { mainColumn.visibleGrid = runnerGrid; } } onKeyNavUp: searchField.focus = true } Keys.onPressed: (event)=> { if(event.modifiers & Qt.ControlModifier ||event.modifiers & Qt.ShiftModifier){ searchField.focus = true; return } if (event.key === Qt.Key_Tab) { event.accepted = true; searchField.focus = true } else if (event.key === Qt.Key_Backspace) { event.accepted = true; if(root.searching) searchField.backspace(); else searchField.focus = true } else if (event.key === Qt.Key_Escape) { event.accepted = true; if(root.searching){ searchField.clear() } else { root.toggle() } } else if (event.text !== "") { event.accepted = true; searchField.appendText(event.text); showApps = 1 } } } } Keys.onPressed: (event)=> { if(event.modifiers & Qt.ControlModifier ||event.modifiers & Qt.ShiftModifier){ searchField.focus = true; return } if (event.key === Qt.Key_Escape) { event.accepted = true; if (root.searching) { reset(); } else { root.visible = false; } return; } if (searchField.focus) { return; } if (event.key === Qt.Key_Backspace) { event.accepted = true; searchField.backspace(); } else if (event.text !== "") { event.accepted = true; searchField.appendText(event.text); } } } function setModels(){ globalFavoritesGrid.model = globalFavorites allAppsGrid.model = rootModel.modelForRow(0); } Component.onCompleted: { rootModel.refreshed.connect(setModels) reset(); rootModel.refresh(); } } }