diff --git a/Plasma Widgets/SevenStart/contents/pics/menu_select.png b/Plasma Widgets/SevenStart/contents/pics/menu_select.png index ada2701..8cbaa18 100644 Binary files a/Plasma Widgets/SevenStart/contents/pics/menu_select.png and b/Plasma Widgets/SevenStart/contents/pics/menu_select.png differ diff --git a/Plasma Widgets/SevenStart/contents/ui/MenuRepresentation.qml b/Plasma Widgets/SevenStart/contents/ui/MenuRepresentation.qml index 73b3e89..cc6d71c 100644 --- a/Plasma Widgets/SevenStart/contents/ui/MenuRepresentation.qml +++ b/Plasma Widgets/SevenStart/contents/ui/MenuRepresentation.qml @@ -511,6 +511,10 @@ PlasmaCore.Dialog { return shortcuts.home else if (val === 5) return shortcuts.movies + else if (val === 6) + return "~/Downloads" + else if (val === 7) + return "/" } } @@ -643,36 +647,7 @@ PlasmaCore.Dialog { size: iconSizeSide //onClicked: executable.exec("dolphin --new-window "+folderDialog.getPath(2)) } - ListDelegate { - text: "Music" - Image { - property bool hovered: false - source: "../pics/menu_select.png" - smooth: true - opacity: hovered ? 1.0 : 0.0 - width: parent.width - height: parent.height - MouseArea { - enabled: !root.hoverDisabled - acceptedButtons: Qt.LeftButton - onEntered: { - parent.hovered = true - } - onExited: { - parent.hovered = false - } - onClicked: { - root.visible = false; - executable.exec("dolphin --new-window "+folderDialog.getPath(3)) - } - hoverEnabled: true - anchors.fill: parent - } - } - icon: "folder-music" - size: iconSizeSide - //onClicked: executable.exec("dolphin --new-window "+folderDialog.getPath(3)) - } + ListDelegate { text: "Pictures" Image { @@ -703,6 +678,36 @@ PlasmaCore.Dialog { size: iconSizeSide //onClicked: executable.exec("dolphin --new-window "+folderDialog.getPath(1)) } + ListDelegate { + text: "Music" + Image { + property bool hovered: false + source: "../pics/menu_select.png" + smooth: true + opacity: hovered ? 1.0 : 0.0 + width: parent.width + height: parent.height + MouseArea { + enabled: !root.hoverDisabled + acceptedButtons: Qt.LeftButton + onEntered: { + parent.hovered = true + } + onExited: { + parent.hovered = false + } + onClicked: { + root.visible = false; + executable.exec("dolphin --new-window "+folderDialog.getPath(3)) + } + hoverEnabled: true + anchors.fill: parent + } + } + icon: "folder-music" + size: iconSizeSide + //onClicked: executable.exec("dolphin --new-window "+folderDialog.getPath(3)) + } ListDelegate { text: "Videos" Image { @@ -733,6 +738,66 @@ PlasmaCore.Dialog { size: iconSizeSide //onClicked: executable.exec("dolphin --new-window "+folderDialog.getPath(5)) } + ListDelegate { + text: "Downloads" + Image { + property bool hovered: false + source: "../pics/menu_select.png" + smooth: true + opacity: hovered ? 1.0 : 0.0 + width: parent.width + height: parent.height + MouseArea { + enabled: !root.hoverDisabled + acceptedButtons: Qt.LeftButton + onEntered: { + parent.hovered = true + } + onExited: { + parent.hovered = false + } + onClicked: { + root.visible = false; + executable.exec("dolphin --new-window "+folderDialog.getPath(6)) + } + hoverEnabled: true + anchors.fill: parent + } + } + icon: "folder-music" + size: iconSizeSide + //onClicked: executable.exec("dolphin --new-window "+folderDialog.getPath(5)) + } + ListDelegate { + text: "Computer" + Image { + property bool hovered: false + source: "../pics/menu_select.png" + smooth: true + opacity: hovered ? 1.0 : 0.0 + width: parent.width + height: parent.height + MouseArea { + enabled: !root.hoverDisabled + acceptedButtons: Qt.LeftButton + onEntered: { + parent.hovered = true + } + onExited: { + parent.hovered = false + } + onClicked: { + root.visible = false; + executable.exec("dolphin --new-window "+folderDialog.getPath(7)) + } + hoverEnabled: true + anchors.fill: parent + } + } + icon: "folder-music" + size: iconSizeSide + //onClicked: executable.exec("dolphin --new-window "+folderDialog.getPath(5)) + } ListDelegate { text: "System Settings" @@ -754,7 +819,37 @@ PlasmaCore.Dialog { } onClicked: { root.visible = false; - logic.openUrl("file:///usr/share/applications/systemsettings.desktop") + executable.exec("systemsettings5") + } + hoverEnabled: true + anchors.fill: parent + } + } + icon: "configure" + size: iconSizeSide + //onClicked: logic.openUrl("file:///usr/share/applications/systemsettings.desktop") + } + ListDelegate { + text: "Default Programs" + Image { + property bool hovered: false + source: "../pics/menu_select.png" + smooth: true + opacity: hovered ? 1.0 : 0.0 + width: parent.width + height: parent.height + MouseArea { + enabled: !root.hoverDisabled + acceptedButtons: Qt.LeftButton + onEntered: { + parent.hovered = true + } + onExited: { + parent.hovered = false + } + onClicked: { + root.visible = false; + executable.exec("systemsettings5 componentchooser") } hoverEnabled: true anchors.fill: parent diff --git a/Plasma Widgets/SevenStart/contents/ui/main.qml b/Plasma Widgets/SevenStart/contents/ui/main.qml index f24234b..5da27b4 100644 --- a/Plasma Widgets/SevenStart/contents/ui/main.qml +++ b/Plasma Widgets/SevenStart/contents/ui/main.qml @@ -44,11 +44,33 @@ Item { property QtObject globalFavorites: rootModel.favoritesModel property QtObject systemFavorites: rootModel.systemFavoritesModel +PlasmaCore.DataSource { + id: menu_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) + } function action_menuedit() { processRunner.runMenuEditor(); } - + function action_taskman() { + menu_executable.exec("ksysguard"); + } + Component { id: compactRepresentation CompactRepresentation {} @@ -197,6 +219,7 @@ Item { Component.onCompleted: { plasmoid.setAction("menuedit", i18n("Edit Applications...")); + plasmoid.setAction("taskman", i18n("Task Manager")); rootModel.refreshed.connect(reset); diff --git a/Plasma Widgets/System Tray/contents/applet/CompactApplet.qml b/Plasma Widgets/System Tray/contents/applet/CompactApplet.qml new file mode 100644 index 0000000..5da557c --- /dev/null +++ b/Plasma Widgets/System Tray/contents/applet/CompactApplet.qml @@ -0,0 +1,83 @@ +/* + * Copyright 2011 Marco Martin + * + * 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 Library 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.1 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.plasmoid 2.0 + + +PlasmaCore.ToolTipArea { + id: appletRoot + objectName: "org.kde.desktop-CompactApplet" + anchors.fill: parent + + mainText: plasmoid.toolTipMainText + subText: plasmoid.toolTipSubText + location: if (plasmoid.parent && plasmoid.parent.inHiddenLayout && plasmoid.location !== PlasmaCore.Types.LeftEdge) { + return PlasmaCore.Types.RightEdge; + } else { + return plasmoid.location; + } + active: !plasmoid.expanded + textFormat: plasmoid.toolTipTextFormat + mainItem: plasmoid.toolTipItem ? plasmoid.toolTipItem : null + + property Item fullRepresentation + property Item compactRepresentation + + Connections { + target: plasmoid + function onContextualActionsAboutToShow() { + appletRoot.hideToolTip() + } + } + + Layout.minimumWidth: { + switch (plasmoid.formFactor) { + case PlasmaCore.Types.Vertical: + return 0; + case PlasmaCore.Types.Horizontal: + return height; + default: + return PlasmaCore.Units.gridUnit * 3; + } + } + + Layout.minimumHeight: { + switch (plasmoid.formFactor) { + case PlasmaCore.Types.Vertical: + return width; + case PlasmaCore.Types.Horizontal: + return 0; + default: + return PlasmaCore.Units.gridUnit * 3; + } + } + + onCompactRepresentationChanged: { + if (compactRepresentation) { + compactRepresentation.parent = appletRoot; + compactRepresentation.anchors.fill = appletRoot; + compactRepresentation.visible = true; + } + appletRoot.visible = true; + } +} + diff --git a/Plasma Widgets/System Tray/contents/config/config.qml b/Plasma Widgets/System Tray/contents/config/config.qml new file mode 100644 index 0000000..e6eeac3 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/config/config.qml @@ -0,0 +1,35 @@ +/*************************************************************************** + * Copyright 2013 by Sebastian Kügler * + * * + * 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.0 + +import org.kde.plasma.configuration 2.0 + +ConfigModel { + ConfigCategory { + name: i18n("General") + icon: "plasma" + source: "ConfigGeneral.qml" + } + ConfigCategory { + name: i18n("Entries") + icon: "preferences-desktop-notification" + source: "ConfigEntries.qml" + } +} diff --git a/Plasma Widgets/System Tray/contents/config/main.xml b/Plasma Widgets/System Tray/contents/config/main.xml new file mode 100644 index 0000000..4e2fdf5 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/config/main.xml @@ -0,0 +1,39 @@ + + + + + + + + + + + + + + + + + + + + false + + + + + false + + + + false + + + + + diff --git a/Plasma Widgets/System Tray/contents/ui/ConfigEntries.qml b/Plasma Widgets/System Tray/contents/ui/ConfigEntries.qml new file mode 100644 index 0000000..3bc9ecb --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/ConfigEntries.qml @@ -0,0 +1,296 @@ +/* + * Copyright 2013 Sebastian Kügler + * Copyright 2014 Marco Martin + * Copyright 2019 Konrad Materka + * + * 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 2.010-1301, USA. + */ + +import QtQuick 2.5 +import QtQuick.Controls 2.5 as QQC2 +import QtQuick.Layouts 1.3 + +import org.kde.kquickcontrols 2.0 as KQC +import org.kde.kirigami 2.10 as Kirigami + +ColumnLayout { + id: iconsPage + + signal configurationChanged + + property var cfg_shownItems: [] + property var cfg_hiddenItems: [] + property var cfg_extraItems: [] + property alias cfg_showAllItems: showAllCheckBox.checked + + QQC2.CheckBox { + id: showAllCheckBox + text: i18n("Always show all entries") + } + + function categoryName(category) { + switch (category) { + case "ApplicationStatus": + return i18n("Application Status") + case "Communications": + return i18n("Communications") + case "SystemServices": + return i18n("System Services") + case "Hardware": + return i18n("Hardware Control") + case "UnknownCategory": + default: + return i18n("Miscellaneous") + } + } + + QQC2.ScrollView { + id: scrollView + + Layout.fillWidth: true + Layout.fillHeight: true + contentHeight: itemsList.implicitHeight + + Component.onCompleted: scrollView.background.visible = true + + property bool scrollBarVisible: QQC2.ScrollBar.vertical && QQC2.ScrollBar.vertical.visible + property var scrollBarWidth: scrollBarVisible ? QQC2.ScrollBar.vertical.width : 0 + + ListView { + id: itemsList + + property var visibilityColumnWidth: Kirigami.Units.gridUnit + property var keySequenceColumnWidth: Kirigami.Units.gridUnit + + clip: true + + model: plasmoid.nativeInterface.configSystemTrayModel + + header: Kirigami.AbstractListItem { + + hoverEnabled: false + + RowLayout { + Kirigami.Heading { + text: i18nc("Name of the system tray entry", "Entry") + level: 2 + Layout.fillWidth: true + } + Kirigami.Heading { + text: i18n("Visibility") + level: 2 + Layout.preferredWidth: itemsList.visibilityColumnWidth + Component.onCompleted: itemsList.visibilityColumnWidth = Math.max(implicitWidth, itemsList.visibilityColumnWidth) + } + Kirigami.Heading { + text: i18n("Keyboard Shortcut") + level: 2 + Layout.preferredWidth: itemsList.keySequenceColumnWidth + Component.onCompleted: itemsList.keySequenceColumnWidth = Math.max(implicitWidth, itemsList.keySequenceColumnWidth) + } + QQC2.Button { // Configure button column + icon.name: "configure" + enabled: false + opacity: 0 + } + } + } + + section { + property: "category" + delegate: Kirigami.ListSectionHeader { + label: categoryName(section) + } + } + + delegate: Kirigami.AbstractListItem { + highlighted: false + hoverEnabled: false + + property bool isPlasmoid: model.itemType === "Plasmoid" + + contentItem: RowLayout { + RowLayout { + Layout.fillWidth: true + + Kirigami.Icon { + implicitWidth: Kirigami.Units.iconSizes.smallMedium + implicitHeight: Kirigami.Units.iconSizes.smallMedium + source: model.decoration + } + QQC2.Label { + Layout.fillWidth: true + text: model.display + elide: Text.ElideRight + wrapMode: Text.NoWrap + } + } + + QQC2.ComboBox { + id: visibilityComboBox + + property var contentWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset, + implicitContentWidth + leftPadding + rightPadding) + implicitWidth: Math.max(contentWidth, itemsList.visibilityColumnWidth) + Component.onCompleted: itemsList.visibilityColumnWidth = Math.max(implicitWidth, itemsList.visibilityColumnWidth) + + enabled: (!showAllCheckBox.checked || isPlasmoid) && itemId + textRole: "text" + model: comboBoxModel() + + currentIndex: { + var value + + if (cfg_shownItems.indexOf(itemId) !== -1) { + value = "shown" + } else if (cfg_hiddenItems.indexOf(itemId) !== -1) { + value = "hidden" + } else if (isPlasmoid && cfg_extraItems.indexOf(itemId) === -1) { + value = "disabled" + } else { + value = "auto" + } + + for (var i = 0; i < model.length; i++) { + if (model[i].value === value) { + return i + } + } + + return 0 + } + + property var myCurrentValue: model[currentIndex].value + + onActivated: { + var shownIndex = cfg_shownItems.indexOf(itemId) + var hiddenIndex = cfg_hiddenItems.indexOf(itemId) + var extraIndex = cfg_extraItems.indexOf(itemId) + + switch (myCurrentValue) { + case "auto": + if (shownIndex > -1) { + cfg_shownItems.splice(shownIndex, 1) + } + if (hiddenIndex > -1) { + cfg_hiddenItems.splice(hiddenIndex, 1) + } + if (extraIndex === -1) { + cfg_extraItems.push(itemId) + } + break + case "shown": + if (shownIndex === -1) { + cfg_shownItems.push(itemId) + } + if (hiddenIndex > -1) { + cfg_hiddenItems.splice(hiddenIndex, 1) + } + if (extraIndex === -1) { + cfg_extraItems.push(itemId) + } + break + case "hidden": + if (shownIndex > -1) { + cfg_shownItems.splice(shownIndex, 1) + } + if (hiddenIndex === -1) { + cfg_hiddenItems.push(itemId) + } + if (extraIndex === -1) { + cfg_extraItems.push(itemId) + } + break + case "disabled": + if (shownIndex > -1) { + cfg_shownItems.splice(shownIndex, 1) + } + if (hiddenIndex > -1) { + cfg_hiddenItems.splice(hiddenIndex, 1) + } + if (extraIndex > -1) { + cfg_extraItems.splice(extraIndex, 1) + } + break + } + iconsPage.configurationChanged() + } + + function comboBoxModel() { + var autoElement = {"value": "auto", "text": i18n("Shown when relevant")} + var shownElement = {"value": "shown", "text": i18n("Always shown")} + var hiddenElement = {"value": "hidden", "text": i18n("Always hidden")} + var disabledElement = {"value": "disabled", "text": i18n("Disabled")} + + if (showAllCheckBox.checked) { + if (isPlasmoid) { + return [autoElement, disabledElement] + } else { + return [shownElement] + } + } else { + if (isPlasmoid) { + return [autoElement, shownElement, hiddenElement, disabledElement] + } else { + return [autoElement, shownElement, hiddenElement] + } + } + } + } + KQC.KeySequenceItem { + id: keySequenceItem + Layout.minimumWidth: itemsList.keySequenceColumnWidth + Layout.preferredWidth: itemsList.keySequenceColumnWidth + Component.onCompleted: itemsList.keySequenceColumnWidth = Math.max(implicitWidth, itemsList.keySequenceColumnWidth) + + visible: isPlasmoid + enabled: visibilityComboBox.myCurrentValue !== "disabled" + keySequence: model.applet ? model.applet.globalShortcut : "" + onKeySequenceChanged: { + if (model.applet && keySequence !== model.applet.globalShortcut) { + model.applet.globalShortcut = keySequence + + itemsList.keySequenceColumnWidth = Math.max(implicitWidth, itemsList.keySequenceColumnWidth) + } + } + } + // Placeholder for when KeySequenceItem is not visible + Item { + Layout.minimumWidth: itemsList.keySequenceColumnWidth + Layout.maximumWidth: itemsList.keySequenceColumnWidth + visible: !keySequenceItem.visible + } + + QQC2.Button { + readonly property QtObject configureAction: (model.applet && model.applet.action("configure")) || null + + Accessible.name: configureAction ? configureAction.text : "" + icon.name: "configure" + enabled: configureAction && configureAction.visible && configureAction.enabled + // Still reserve layout space, so not setting visible to false + opacity: enabled ? 1 : 0 + onClicked: configureAction.trigger() + + QQC2.ToolTip { + // Strip out ampersands right before non-whitespace characters, i.e. + // those used to determine the alt key shortcut + text: parent.Accessible.name.replace(/&(?=\S)/g, "") + } + } + } + } + } + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/ConfigGeneral.qml b/Plasma Widgets/System Tray/contents/ui/ConfigGeneral.qml new file mode 100644 index 0000000..e2b3de7 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/ConfigGeneral.qml @@ -0,0 +1,49 @@ + + +/*************************************************************************** + * Copyright (C) 2020 Konrad Materka * + * * + * 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.14 +import QtQuick.Controls 2.14 as QQC2 +import QtQuick.Layouts 1.13 + +import org.kde.plasma.core 2.1 as PlasmaCore + +import org.kde.kirigami 2.13 as Kirigami + +ColumnLayout { + property bool cfg_scaleIconsToFit + + Kirigami.FormLayout { + Layout.fillHeight: true + + QQC2.RadioButton { + Kirigami.FormData.label: i18nc("The arrangement of system tray icons in the Panel", "Panel icon size:") + text: i18n("Small") + checked: cfg_scaleIconsToFit == false + onToggled: cfg_scaleIconsToFit = !checked + } + QQC2.RadioButton { + id: automaticRadioButton + text: plasmoid.formFactor === PlasmaCore.Types.Horizontal ? i18n("Scale with Panel height") + : i18n("Scale with Panel width") + checked: cfg_scaleIconsToFit == true + onToggled: cfg_scaleIconsToFit = checked + } + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/CurrentItemHighLight.qml b/Plasma Widgets/System Tray/contents/ui/CurrentItemHighLight.qml new file mode 100644 index 0000000..59f731c --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/CurrentItemHighLight.qml @@ -0,0 +1,182 @@ +/* + * Copyright 2011 Marco Martin + * + * 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 Library 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.12 +import org.kde.plasma.plasmoid 2.0 +import org.kde.plasma.core 2.0 as PlasmaCore + +PlasmaCore.FrameSvgItem { + id: currentItemHighLight + + property int location + + property bool animationEnabled: true + property var highlightedItem: null + + z: -1 // always draw behind icons + opacity: systemTrayState.expanded ? 0.8 : 0 + + MouseArea + { + id: trayItemHighlight + + anchors.fill: parent + + hoverEnabled: true + property int highlightOpacity: 0 + onEntered: highlightOpacity = 1 + onExited: highlightOpacity = 0 + } + + + imagePath: "widgets/tabbar" + prefix: { + var prefix = "" + switch (location) { + case PlasmaCore.Types.LeftEdge: + prefix = "west-active-tab"; + break; + case PlasmaCore.Types.TopEdge: + prefix = "north-active-tab"; + break; + case PlasmaCore.Types.RightEdge: + prefix = "east-active-tab"; + break; + default: + prefix = "south-active-tab"; + } + if (!hasElementPrefix(prefix)) { + prefix = "active-tab"; + } + return prefix; + } + + // update when System Tray is expanded - applet activated or hidden icons shown + Connections { + target: systemTrayState + + function onActiveAppletChanged() { + Qt.callLater(updateHighlightedItem); + } + + function onExpandedChanged() { + Qt.callLater(updateHighlightedItem); + } + } + + // update when applet changes parent (e.g. moves from active to hidden icons) + Connections { + target: systemTrayState.activeApplet + + function onParentChanged() { + Qt.callLater(updateHighlightedItem); + } + } + + // update when System Tray size changes + Connections { + target: parent + + function onWidthChanged() { + Qt.callLater(updateHighlightedItem); + } + + function onHeightChanged() { + Qt.callLater(updateHighlightedItem); + } + } + + // update when scale of newly added tray item changes (check 'add' animation in GridView in main.qml) + Connections { + target: !!highlightedItem && highlightedItem.parent ? highlightedItem.parent : null + + function onScaleChanged() { + Qt.callLater(updateHighlightedItem); + } + } + + function updateHighlightedItem() { + if (systemTrayState.expanded) { + if (systemTrayState.activeApplet && systemTrayState.activeApplet.parent && systemTrayState.activeApplet.parent.inVisibleLayout) { + changeHighlightedItem(systemTrayState.activeApplet.parent.container); + } else { // 'Show hiden items' popup + changeHighlightedItem(parent); + } + } else { + highlightedItem = null; + } + } + + function changeHighlightedItem(nextItem) { + // do not animate the first appearance + // or when the property value of a highlighted item changes + if (!highlightedItem || (highlightedItem === nextItem)) { + animationEnabled = false; + } + + highlightedItem = nextItem; + + const p = parent.mapFromItem(highlightedItem, 0, 0) + x = p.x; + y = p.y; + width = highlightedItem.width + height = highlightedItem.height + + animationEnabled = true; + } + + Behavior on opacity { + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: systemTrayState.expanded ? Easing.OutCubic : Easing.InCubic + } + } + Behavior on x { + id: xAnim + enabled: animationEnabled + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutCubic + } + } + Behavior on y { + id: yAnim + enabled: animationEnabled + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutCubic + } + } + Behavior on width { + id: widthAnim + enabled: animationEnabled + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutCubic + } + } + Behavior on height { + id: heightAnim + enabled: animationEnabled + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutCubic + } + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/ExpandedRepresentation.qml b/Plasma Widgets/System Tray/contents/ui/ExpandedRepresentation.qml new file mode 100644 index 0000000..714aae2 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/ExpandedRepresentation.qml @@ -0,0 +1,231 @@ +/* + * Copyright 2016 Marco Martin + * Copyright 2020 Nate Graham + * + * 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 Library 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.12 +import QtQuick.Layouts 1.12 + +import org.kde.plasma.core 2.0 as PlasmaCore +// We still need PC2 here for that version of Menu, as PC2 Menu is still very problematic with QActions +// Not being a proper popup window, makes it a showstopper to be used in Plasma +import org.kde.plasma.components 2.0 as PC2 +import org.kde.plasma.components 3.0 as PlasmaComponents +import org.kde.plasma.extras 2.0 as PlasmaExtras + +Item { + id: popup + //set width/height to avoid useless Dialog resize + readonly property int defaultWidth: PlasmaCore.Units.gridUnit * 24 + readonly property int defaultHeight: PlasmaCore.Units.gridUnit * 24 + + width: defaultWidth + Layout.minimumWidth: defaultWidth + Layout.preferredWidth: defaultWidth + Layout.maximumWidth: defaultWidth + + height: defaultHeight + Layout.minimumHeight: defaultHeight + Layout.preferredHeight: defaultHeight + Layout.maximumHeight: defaultHeight + + property alias hiddenLayout: hiddenItemsView.layout + + // Header + PlasmaExtras.PlasmoidHeading { + id: plasmoidHeading + anchors { + top: parent.top + left: parent.left + right: parent.right + } + height: trayHeading.height + bottomPadding + container.headingHeight + Behavior on height { + NumberAnimation { duration: PlasmaCore.Units.shortDuration/2; easing.type: Easing.InOutQuad } + } + } + + // Main content layout + ColumnLayout { + id: expandedRepresentation + anchors.fill: parent + // TODO: remove this so the scrollview fully touches the header; + // add top padding internally + spacing: plasmoidHeading.bottomPadding + + // Header content layout + RowLayout { + id: trayHeading + + PlasmaComponents.ToolButton { + id: backButton + visible: systemTrayState.activeApplet && systemTrayState.activeApplet.expanded && (hiddenLayout.itemCount > 0) + icon.name: LayoutMirroring.enabled ? "go-previous-symbolic-rtl" : "go-previous-symbolic" + onClicked: systemTrayState.setActiveApplet(null) + } + + PlasmaExtras.Heading { + Layout.fillWidth: true + leftPadding: systemTrayState.activeApplet ? 0 : PlasmaCore.Units.smallSpacing * 2 + + level: 1 + text: systemTrayState.activeApplet ? systemTrayState.activeApplet.title : i18n("Status and Notifications") + } + + PlasmaComponents.ToolButton { + id: actionsButton + visible: visibleActions > 0 + checked: visibleActions > 1 ? configMenu.status !== PC2.DialogStatus.Closed : singleAction && singleAction.checked + property QtObject applet: systemTrayState.activeApplet || plasmoid + onAppletChanged: { + configMenu.clearMenuItems(); + updateVisibleActions(); + } + property int visibleActions: 0 + property QtObject singleAction + + function updateVisibleActions() { + let newSingleAction = null; + let newVisibleActions = 0; + for (let i in applet.contextualActions) { + let action = applet.contextualActions[i]; + if (action.visible && action !== actionsButton.applet.action("configure")) { + newVisibleActions++; + newSingleAction = action; + action.changed.connect(() => {updateVisibleActions()}); + } + } + if (newVisibleActions > 1) { + newSingleAction = null; + } + visibleActions = newVisibleActions; + singleAction = newSingleAction; + } + Connections { + target: actionsButton.applet + function onContextualActionsChanged() { + Qt.callLater(actionsButton.updateVisibleActions); + } + } + icon.name: "application-menu" + checkable: visibleActions > 1 || (singleAction && singleAction.checkable) + contentItem.opacity: visibleActions > 1 + // NOTE: it needs an IconItem because QtQuickControls2 buttons cannot load QIcons as their icon + PlasmaCore.IconItem { + parent: actionsButton + anchors.centerIn: parent + active: actionsButton.hovered + implicitWidth: PlasmaCore.Units.iconSizes.smallMedium + implicitHeight: implicitWidth + source: actionsButton.singleAction !== null ? actionsButton.singleAction.icon : "" + visible: actionsButton.singleAction + } + onToggled: { + if (visibleActions > 1) { + if (checked) { + configMenu.openRelative(); + } else { + configMenu.close(); + } + } + } + onClicked: { + if (singleAction) { + singleAction.trigger(); + } + } + PlasmaComponents.ToolTip { + text: actionsButton.singleAction ? actionsButton.singleAction.text : i18n("More actions") + } + PC2.Menu { + id: configMenu + visualParent: actionsButton + placement: PlasmaCore.Types.BottomPosedLeftAlignedPopup + } + + Instantiator { + model: actionsButton.applet.contextualActions + delegate: PC2.MenuItem { + id: menuItem + action: modelData + } + onObjectAdded: { + if (object.action !== actionsButton.applet.action("configure")) { + configMenu.addMenuItem(object); + } + } + } + } + PlasmaComponents.ToolButton { + icon.name: "configure" + visible: actionsButton.applet && actionsButton.applet.action("configure") + PlasmaComponents.ToolTip { + text: parent.visible ? actionsButton.applet.action("configure").text : "" + } + onClicked: actionsButton.applet.action("configure").trigger(); + } + + PlasmaComponents.ToolButton { + id: pinButton + checkable: true + checked: plasmoid.configuration.pin + onToggled: plasmoid.configuration.pin = checked + icon.name: "window-pin" + PlasmaComponents.ToolTip { + text: i18n("Keep Open") + } + } + } + + // Grid view of all available items + HiddenItemsView { + id: hiddenItemsView + Layout.fillWidth: true + Layout.fillHeight: true + Layout.topMargin: PlasmaCore.Units.smallSpacing + visible: !systemTrayState.activeApplet + } + + // Container for currently visible item + PlasmoidPopupsContainer { + id: container + Layout.fillWidth: true + Layout.fillHeight: true + visible: systemTrayState.activeApplet + + // We need to add margin on the top so it matches the dialog's own margin + Layout.topMargin: mergeHeadings ? 0 : dialog.margins.top + } + } + + // Footer + PlasmaExtras.PlasmoidHeading { + id: plasmoidFooter + location: PlasmaExtras.PlasmoidHeading.Location.Footer + anchors { + bottom: parent.bottom + left: parent.left + right: parent.right + } + visible: container.appletHasFooter + height: container.footerHeight + // So that it doesn't appear over the content view, which results in + // the footer controls being inaccessible + z: -9999 + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/ExpanderArrow.qml b/Plasma Widgets/System Tray/contents/ui/ExpanderArrow.qml new file mode 100644 index 0000000..74b740f --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/ExpanderArrow.qml @@ -0,0 +1,112 @@ +/*************************************************************************** + * Copyright 2013 Sebastian Kügler * + * Copyright 2015 Marco Martin * + * * + * 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 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 Library 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.0 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore + +PlasmaCore.ToolTipArea { + id: tooltip + + property bool vertical: plasmoid.formFactor === PlasmaCore.Types.Vertical + implicitWidth: PlasmaCore.Units.iconSizes.smallMedium + implicitHeight: implicitWidth + + subText: systemTrayState.expanded ? i18n("Close popup") : i18n("Show hidden icons") + + MouseArea { + id: arrowMouseArea + anchors.fill: parent + onClicked: systemTrayState.expanded = !systemTrayState.expanded + + readonly property int arrowAnimationDuration: PlasmaCore.Units.shortDuration + + PlasmaCore.Svg { + id: arrowSvg + imagePath: "widgets/arrows" + } + + PlasmaCore.SvgItem { + id: arrow + + anchors.centerIn: parent + width: Math.min(parent.width, parent.height) + height: width + + rotation: systemTrayState.expanded ? 180 : 0 + Behavior on rotation { + RotationAnimation { + duration: arrowMouseArea.arrowAnimationDuration + } + } + opacity: systemTrayState.expanded ? 0 : 1 + Behavior on opacity { + NumberAnimation { + duration: arrowMouseArea.arrowAnimationDuration + } + } + + svg: arrowSvg + elementId: { + if (plasmoid.location === PlasmaCore.Types.TopEdge) { + return "down-arrow"; + } else if (plasmoid.location === PlasmaCore.Types.LeftEdge) { + return "right-arrow"; + } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { + return "left-arrow"; + } else { + return "up-arrow"; + } + } + } + + PlasmaCore.SvgItem { + anchors.centerIn: parent + width: arrow.width + height: arrow.height + + rotation: systemTrayState.expanded ? 0 : -180 + Behavior on rotation { + RotationAnimation { + duration: arrowMouseArea.arrowAnimationDuration + } + } + opacity: systemTrayState.expanded ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: arrowMouseArea.arrowAnimationDuration + } + } + + svg: arrowSvg + elementId: { + if (plasmoid.location === PlasmaCore.Types.TopEdge) { + return "up-arrow"; + } else if (plasmoid.location === PlasmaCore.Types.LeftEdge) { + return "left-arrow"; + } else if (plasmoid.location === PlasmaCore.Types.RightEdge) { + return "right-arrow"; + } else { + return "down-arrow"; + } + } + } + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/HiddenItemsView.qml b/Plasma Widgets/System Tray/contents/ui/HiddenItemsView.qml new file mode 100644 index 0000000..f7c45c8 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/HiddenItemsView.qml @@ -0,0 +1,71 @@ +/* + * Copyright 2016 Marco Martin + * Copyright 2020 Konrad Materka + * Copyright 2020 Nate Graham + * + * 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 Library 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.1 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.1 as PlasmaCore +import org.kde.plasma.components 2.0 as PlasmaComponents // For Highlight +import org.kde.plasma.extras 2.0 as PlasmaExtras + +import "items" + +MouseArea { + id: hiddenTasksView + + property alias layout: hiddenTasks + + hoverEnabled: true + onExited: hiddenTasks.currentIndex = -1 + + PlasmaExtras.ScrollArea { + width: parent.width + height: parent.height + frameVisible: false + + horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff + verticalScrollBarPolicy: systemTrayState.activeApplet ? Qt.ScrollBarAlwaysOff : Qt.ScrollBarAsNeeded + + GridView { + id: hiddenTasks + + readonly property int rows: 4 + readonly property int columns: 4 + + cellWidth: hiddenTasks.width / hiddenTasks.columns + cellHeight: hiddenTasks.height / hiddenTasks.rows + + currentIndex: -1 + highlight: PlasmaComponents.Highlight {} + highlightMoveDuration: 0 + + readonly property int itemCount: model.count + + model: PlasmaCore.SortFilterModel { + sourceModel: plasmoid.nativeInterface.systemTrayModel + filterRole: "effectiveStatus" + filterCallback: function(source_row, value) { + return value === PlasmaCore.Types.PassiveStatus + } + } + delegate: ItemLoader {} + } + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/PlasmoidPopupsContainer.qml b/Plasma Widgets/System Tray/contents/ui/PlasmoidPopupsContainer.qml new file mode 100644 index 0000000..0a7d200 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/PlasmoidPopupsContainer.qml @@ -0,0 +1,157 @@ +/* + * Copyright 2015 Marco Martin + * + * 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 Library 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 QtQuick.Layouts 1.1 +import QtQuick.Controls 1.4 +//needed for units +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents3 +import org.kde.plasma.extras 2.0 as PlasmaExtras + +StackView { + id: mainStack + focus: true + + Layout.minimumWidth: PlasmaCore.Units.gridUnit * 12 + Layout.minimumHeight: PlasmaCore.Units.gridUnit * 12 + + readonly property Item activeApplet: systemTrayState.activeApplet + + /* Heading */ + property bool appletHasHeading: false + property bool mergeHeadings: appletHasHeading && activeApplet.fullRepresentationItem.header.visible + property int headingHeight: mergeHeadings ? activeApplet.fullRepresentationItem.header.height : 0 + /* Footer */ + property bool appletHasFooter: false + property bool mergeFooters: appletHasFooter && activeApplet.fullRepresentationItem.footer.visible + property int footerHeight: mergeFooters ? activeApplet.fullRepresentationItem.footer.height : 0 + + onActiveAppletChanged: { + mainStack.appletHasHeading = false + mainStack.appletHasFooter = false + if (activeApplet != null) { + //reset any potential anchor + activeApplet.fullRepresentationItem.anchors.left = undefined; + activeApplet.fullRepresentationItem.anchors.top = undefined; + activeApplet.fullRepresentationItem.anchors.right = undefined; + activeApplet.fullRepresentationItem.anchors.bottom = undefined; + activeApplet.fullRepresentationItem.anchors.centerIn = undefined; + activeApplet.fullRepresentationItem.anchors.fill = undefined; + + if (activeApplet.fullRepresentationItem instanceof PlasmaComponents3.Page) { + if (activeApplet.fullRepresentationItem.header && activeApplet.fullRepresentationItem.header instanceof PlasmaExtras.PlasmoidHeading) { + mainStack.appletHasHeading = true + activeApplet.fullRepresentationItem.header.background.visible = false + } + if (activeApplet.fullRepresentationItem.footer && activeApplet.fullRepresentationItem.footer instanceof PlasmaExtras.PlasmoidHeading) { + mainStack.appletHasFooter = true + activeApplet.fullRepresentationItem.footer.background.visible = false + } + } + + mainStack.replace({item: activeApplet.fullRepresentationItem, immediate: !systemTrayState.expanded, properties: {focus: true}}); + } else { + mainStack.replace(emptyPage); + } + } + + onCurrentItemChanged: { + if (currentItem !== null && plasmoid.expanded) { + currentItem.forceActiveFocus(); + } + } + + Connections { + target: plasmoid + function onAppletRemoved(applet) { + if (applet === systemTrayState.activeApplet) { + mainStack.clear() + } + } + } + //used to animate away to nothing + Item { + id: emptyPage + } + + delegate: StackViewDelegate { + id: transitioner + function transitionFinished(properties) { + properties.exitItem.opacity = 1 + } + property bool goingLeft: { + const unFlipped = systemTrayState.oldVisualIndex < systemTrayState.newVisualIndex + + if (Qt.application.layoutDirection == Qt.LeftToRight) { + return unFlipped + } else { + return !unFlipped + } + } + replaceTransition: StackViewTransition { + ParallelAnimation { + PropertyAnimation { + target: enterItem + property: "x" + from: root.vertical ? 0 : (transitioner.goingLeft ? enterItem.width : -enterItem.width) + to: 0 + easing.type: Easing.InOutQuad + duration: PlasmaCore.Units.shortDuration + } + SequentialAnimation { + PropertyAction { + target: enterItem + property: "opacity" + value: 0 + } + PauseAnimation { + duration: root.vertical ? (PlasmaCore.Units.shortDuration/2) : 0 + } + PropertyAnimation { + target: enterItem + property: "opacity" + from: 0 + to: 1 + easing.type: Easing.InOutQuad + duration: (PlasmaCore.Units.shortDuration/2) + } + } + } + ParallelAnimation { + PropertyAnimation { + target: exitItem + property: "x" + from: 0 + to: root.vertical ? 0 : (transitioner.goingLeft ? -exitItem.width : exitItem.width) + easing.type: Easing.InOutQuad + duration: PlasmaCore.Units.shortDuration + } + PropertyAnimation { + target: exitItem + property: "opacity" + from: 1 + to: 0 + easing.type: Easing.InOutQuad + duration: PlasmaCore.Units.shortDuration/2 + } + } + } + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/SystemTrayState.qml b/Plasma Widgets/System Tray/contents/ui/SystemTrayState.qml new file mode 100644 index 0000000..edf9ca3 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/SystemTrayState.qml @@ -0,0 +1,107 @@ +/* + * Copyright 2020 Konrad Materka + * + * 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 Library 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.12 +import org.kde.plasma.core 2.1 as PlasmaCore +import org.kde.plasma.plasmoid 2.0 + +//This object contains state of the SystemTray, mainly related to the 'expanded' state +QtObject { + //true if System Tray is 'expanded'. It may be when: + // - there is an active applet or + // - 'Status and Notification' with hidden items is shown + property bool expanded: false + //set when there is an applet selected + property Item activeApplet + + //allow expanded change only when activated at least once + //this is to suppress expanded state change during Plasma startup + property bool acceptExpandedChange: false + + // These properties allow us to keep track of where the expanded applet + // was and is on the panel, allowing PlasmoidPopupContainer.qml to animate + // depending on their locations. + property int oldVisualIndex: -1 + property int newVisualIndex: -1 + + function setActiveApplet(applet, visualIndex) { + if (visualIndex === undefined) { + oldVisualIndex = -1 + newVisualIndex = -1 + } else { + oldVisualIndex = newVisualIndex + newVisualIndex = visualIndex + } + + const oldApplet = activeApplet + activeApplet = applet + if (oldApplet && oldApplet !== applet) { + oldApplet.expanded = false + } + expanded = true + } + + onExpandedChanged: { + if (expanded) { + plasmoid.status = PlasmaCore.Types.RequiresAttentionStatus + } else { + plasmoid.status = PlasmaCore.Types.PassiveStatus; + if (activeApplet) { + // if not expanded we don't have an active applet anymore + activeApplet.expanded = false + activeApplet = null + } + } + acceptExpandedChange = false + plasmoid.expanded = expanded + } + + //listen on SystemTray AppletInterface signals + property Connections plasmoidConnections: Connections { + target: plasmoid + //emitted when activation is requested, for example by using a global keyboard shortcut + function onActivated() { + acceptExpandedChange = true + } + //emitted when the configuration dialog is opened + function onUserConfiguringChanged() { + if (plasmoid.userConfiguring) { + systemTrayState.expanded = false + } + } + function onExpandedChanged() { + if (acceptExpandedChange) { + expanded = plasmoid.expanded + } else { + plasmoid.expanded = expanded + } + } + } + + property Connections activeAppletConnections: Connections { + target: activeApplet + + function onExpandedChanged() { + if (!activeApplet.expanded) { + expanded = false + } + } + } + +} diff --git a/Plasma Widgets/System Tray/contents/ui/items/AbstractItem.qml b/Plasma Widgets/System Tray/contents/ui/items/AbstractItem.qml new file mode 100644 index 0000000..b2c7c72 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/items/AbstractItem.qml @@ -0,0 +1,216 @@ +/* + * Copyright 2016 Marco Martin + * Copyright 2020 Konrad Materka + * Copyright 2020 Nate Graham + * + * 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 Library 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 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.0 as PlasmaCore +import org.kde.plasma.components 3.0 as PlasmaComponents3 + +PlasmaCore.ToolTipArea { + id: abstractItem + + height: inVisibleLayout ? visibleLayout.cellHeight : hiddenTasks.cellHeight + width: inVisibleLayout ? visibleLayout.cellWidth : hiddenTasks.cellWidth + + property var model: itemModel + + property string itemId + property alias text: label.text + property alias iconContainer: iconContainer + property int /*PlasmaCore.Types.ItemStatus*/ status: model.status || PlasmaCore.Types.UnknownStatus + property int /*PlasmaCore.Types.ItemStatus*/ effectiveStatus: model.effectiveStatus || PlasmaCore.Types.UnknownStatus + readonly property bool inHiddenLayout: effectiveStatus === PlasmaCore.Types.PassiveStatus + readonly property bool inVisibleLayout: effectiveStatus === PlasmaCore.Types.ActiveStatus + + signal clicked(var mouse) + signal pressed(var mouse) + signal wheel(var wheel) + signal contextMenu(var mouse) + + /* subclasses need to assign to this tooltip properties + mainText: + subText: + */ + + location: { + if (inHiddenLayout) { + if (LayoutMirroring.enabled && plasmoid.location !== PlasmaCore.Types.RightEdge) { + return PlasmaCore.Types.LeftEdge; + } else if (plasmoid.location !== PlasmaCore.Types.LeftEdge) { + return PlasmaCore.Types.RightEdge; + } + } + + return plasmoid.location; + } + +//BEGIN CONNECTIONS + + onContainsMouseChanged: { + if (inHiddenLayout && containsMouse) { + root.hiddenLayout.currentIndex = index + } + else if(!inHiddenLayout) { + itemHighLight.opacity = containsMouse ? 1 : 0 + } + + } + +//END CONNECTIONS + + PlasmaCore.FrameSvgItem { + id: itemHighLight + anchors.fill: parent + property int location + + property bool animationEnabled: true + property var highlightedItem: null + + z: -1 // always draw behind icons + opacity: 0 + + imagePath: "widgets/tabbar" + prefix: { + var prefix = "" + switch (location) { + case PlasmaCore.Types.LeftEdge: + prefix = "west-active-tab"; + break; + case PlasmaCore.Types.TopEdge: + prefix = "north-active-tab"; + break; + case PlasmaCore.Types.RightEdge: + prefix = "east-active-tab"; + break; + default: + prefix = "south-active-tab"; + } + if (!hasElementPrefix(prefix)) { + prefix = "active-tab"; + } + return prefix; + } + Behavior on opacity { + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutQuad + //easing.type: systemTrayState.expanded ? Easing.OutCubic : Easing.InCubic + } + } + } + PulseAnimation { + targetItem: iconContainer + running: (abstractItem.status === PlasmaCore.Types.NeedsAttentionStatus || + abstractItem.status === PlasmaCore.Types.RequiresAttentionStatus ) && + PlasmaCore.Units.longDuration > 0 + } + + function activated() { + //activatedAnimation.start() + } + + SequentialAnimation { + id: activatedAnimation + loops: 1 + + ScaleAnimator { + target: iconContainer + from: 1 + to: 0.5 + duration: PlasmaCore.Units.shortDuration + easing.type: Easing.InQuad + } + + ScaleAnimator { + target: iconContainer + from: 0.5 + to: 1 + duration: PlasmaCore.Units.shortDuration + easing.type: Easing.OutQuad + } + } + + MouseArea { + anchors.fill: abstractItem + hoverEnabled: true + drag.filterChildren: true + acceptedButtons: Qt.LeftButton | Qt.MiddleButton | Qt.RightButton + onClicked: abstractItem.clicked(mouse) + onPressed: { + abstractItem.hideToolTip() + abstractItem.pressed(mouse) + } + onPressAndHold: { + abstractItem.contextMenu(mouse) + } + onWheel: { + abstractItem.wheel(wheel); + //Don't accept the event in order to make the scrolling by mouse wheel working + //for the parent scrollview this icon is in. + wheel.accepted = false; + } + } + + ColumnLayout { + anchors.fill: abstractItem + spacing: 0 + + Item { + id: iconContainer + + property alias container: abstractItem + property alias inVisibleLayout: abstractItem.inVisibleLayout + readonly property int size: abstractItem.inVisibleLayout ? root.itemSize : PlasmaCore.Units.iconSizes.medium + + Layout.alignment: Qt.Bottom | Qt.AlignHCenter + Layout.fillHeight: abstractItem.inHiddenLayout ? true : false + implicitWidth: root.vertical && abstractItem.inVisibleLayout ? abstractItem.width : size + implicitHeight: !root.vertical && abstractItem.inVisibleLayout ? abstractItem.height : size + Layout.topMargin: abstractItem.inHiddenLayout ? Math.round(PlasmaCore.Units.smallSpacing * 1.5): 0 + } + PlasmaComponents3.Label { + id: label + + Layout.fillWidth: true + Layout.fillHeight: abstractItem.inHiddenLayout ? true : false + Layout.leftMargin: abstractItem.inHiddenLayout ? PlasmaCore.Units.smallSpacing : 0 + Layout.rightMargin: abstractItem.inHiddenLayout ? PlasmaCore.Units.smallSpacing : 0 + Layout.bottomMargin: abstractItem.inHiddenLayout ? PlasmaCore.Units.smallSpacing : 0 + + visible: abstractItem.inHiddenLayout + + verticalAlignment: Text.AlignTop + horizontalAlignment: Text.AlignHCenter + elide: Text.ElideRight + wrapMode: Text.Wrap + maximumLineCount: 3 + + opacity: visible ? 1 : 0 + Behavior on opacity { + NumberAnimation { + duration: PlasmaCore.Units.longDuration + easing.type: Easing.InOutQuad + } + } + } + } +} + diff --git a/Plasma Widgets/System Tray/contents/ui/items/ItemLoader.qml b/Plasma Widgets/System Tray/contents/ui/items/ItemLoader.qml new file mode 100644 index 0000000..64034f5 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/items/ItemLoader.qml @@ -0,0 +1,36 @@ +/* + * Copyright 2020 Konrad Materka + * + * 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 Library 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.0 + +Loader { + id: itemLoader + + property var itemModel: model + + source: { + if (model.itemType === "Plasmoid" && model.hasApplet) { + return "PlasmoidItem.qml" + } else if (model.itemType === "StatusNotifier") { + return "StatusNotifierItem.qml" + } + console.warn("SystemTray ItemLoader: Invalid state, cannot determine source!") + return "" + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/items/PlasmoidItem.qml b/Plasma Widgets/System Tray/contents/ui/items/PlasmoidItem.qml new file mode 100644 index 0000000..5592e57 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/items/PlasmoidItem.qml @@ -0,0 +1,141 @@ +/* + * Copyright 2015 Marco Martin + * + * 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 Library 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.1 +import QtQml 2.15 + +import org.kde.plasma.core 2.0 as PlasmaCore + +AbstractItem { + id: plasmoidContainer + + property Item applet: model.applet || null + text: applet ? applet.title : "" + + itemId: applet ? applet.pluginName : "" + mainText: applet ? applet.toolTipMainText : "" + subText: applet ? applet.toolTipSubText : "" + mainItem: applet && applet.toolTipItem ? applet.toolTipItem : null + textFormat: applet ? applet.toolTipTextFormat : "" + active: systemTrayState.activeApplet !== applet + + onClicked: { + if (!applet) { + return + } + //forward click event to the applet + if (mouse.button === Qt.LeftButton || mouse.button === Qt.MidButton) { + const mouseArea = findMouseArea(applet.compactRepresentationItem) + if (mouseArea) { + mouseArea.clicked(mouse) + } else if (mouse.button === Qt.LeftButton) {//falback + applet.expanded = true + } + } + } + onPressed: { + if (mouse.button === Qt.RightButton) { + plasmoidContainer.contextMenu(mouse); + } + } + onContextMenu: { + if (applet) { + plasmoid.nativeInterface.showPlasmoidMenu(applet, 0, plasmoidContainer.inHiddenLayout ? applet.height : 0); + } + } + onWheel: { + if (!applet) { + return + } + //forward wheel event to the applet + const mouseArea = findMouseArea(applet.compactRepresentationItem) + if (mouseArea) { + mouseArea.wheel(wheel) + } + } + + //some heuristics to find MouseArea + function findMouseArea(item) { + if (!item) { + return null + } + + if (item instanceof MouseArea) { + return item + } + for (var i = 0; i < item.children.length; i++) { + const child = item.children[i] + if (child instanceof MouseArea && child.enabled) { + //check if MouseArea covers the entire item + if (child.anchors.fill === item || (child.x === 0 && child.y === 0 && child.height === item.height && child.width === item.width)) { + return child + } + } + } + + return null + } + + //This is to make preloading effective, minimizes the scene changes + function preloadFullRepresentationItem(fullRepresentationItem) { + if (fullRepresentationItem && fullRepresentationItem.parent === null) { + fullRepresentationItem.width = expandedRepresentation.width + fullRepresentationItem.width = expandedRepresentation.height + fullRepresentationItem.parent = preloadedStorage; + } + } + + onAppletChanged: { + if (applet) { + applet.parent = plasmoidContainer.iconContainer + applet.anchors.fill = applet.parent + applet.visible = true + + preloadFullRepresentationItem(applet.fullRepresentationItem) + } + } + + Connections { + target: applet + + //activation using global keyboard shortcut + function onActivated() { + plasmoidContainer.activated() + } + + function onExpandedChanged(expanded) { + if (expanded) { + systemTrayState.setActiveApplet(applet, model.row) + plasmoidContainer.activated() + } + } + + function onFullRepresentationItemChanged(fullRepresentationItem) { + preloadFullRepresentationItem(fullRepresentationItem) + } + } + + Binding { + property: "hideOnWindowDeactivate" + value: !plasmoid.configuration.pin + target: plasmoidContainer.applet + when: null !== plasmoidContainer.applet + restoreMode: Binding.RestoreBinding + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/items/PulseAnimation.qml b/Plasma Widgets/System Tray/contents/ui/items/PulseAnimation.qml new file mode 100644 index 0000000..0506a35 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/items/PulseAnimation.qml @@ -0,0 +1,53 @@ +/* + * Copyright 2013 Sebastian Kügler + * Copyright 2015 Kai Uwe Broulik + * + * 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 Library 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 2.010-1301, USA. + */ + +import QtQuick 2.2 +import org.kde.plasma.core 2.0 as PlasmaCore + +SequentialAnimation { + id: pulseAnimation + objectName: "pulseAnimation" + + property Item targetItem + readonly property int duration: PlasmaCore.Units.veryLongDuration * 5 + + loops: Animation.Infinite + alwaysRunToEnd: true + + ScaleAnimator { + target: targetItem + from: 1 + to: 1.2 + duration: pulseAnimation.duration * 0.15 + easing.type: Easing.InQuad + } + + ScaleAnimator { + target: targetItem + from: 1.2 + to: 1 + duration: pulseAnimation.duration * 0.15 + easing.type: Easing.InQuad + } + + PauseAnimation { + duration: pulseAnimation.duration * 0.7 + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/items/StatusNotifierItem.qml b/Plasma Widgets/System Tray/contents/ui/items/StatusNotifierItem.qml new file mode 100644 index 0000000..e7c1571 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/items/StatusNotifierItem.qml @@ -0,0 +1,118 @@ +/* + * Copyright 2016 Marco Martin + * + * 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 Library 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.1 +import org.kde.plasma.core 2.0 as PlasmaCore + +AbstractItem { + id: taskIcon + + itemId: model.Id + text: model.Title || model.ToolTipTitle + mainText: model.ToolTipTitle !== "" ? model.ToolTipTitle : model.Title + subText: model.ToolTipSubTitle + textFormat: Text.AutoText + + PlasmaCore.IconItem { + id: iconItem + parent: taskIcon.iconContainer + anchors.fill: iconItem.parent + + source: { + if (model.status === PlasmaCore.Types.NeedsAttentionStatus) { + if (model.AttentionIcon) { + return model.AttentionIcon + } + if (model.AttentionIconName) { + return model.AttentionIconName + } + } + return model.Icon ? model.Icon : model.IconName + } + active: taskIcon.containsMouse + } + + onContextMenu: { + openContextMenu(plasmoid.nativeInterface.popupPosition(taskIcon, mouse.x, mouse.y)) + } + + onClicked: { + var pos = plasmoid.nativeInterface.popupPosition(taskIcon, mouse.x, mouse.y); + var service = model.Service; + + switch (mouse.button) { + case Qt.LeftButton: + var operation = service.operationDescription("Activate"); + operation.x = pos.x; + operation.y = pos.y; + var job = service.startOperationCall(operation); + job.finished.connect(function () { + if (!job.result) { + // On error try to invoke the context menu. + // Workaround primarily for apps using libappindicator. + openContextMenu(pos); + } + }); + taskIcon.activated() + break; + case Qt.RightButton: + openContextMenu(pos); + break; + + case Qt.MiddleButton: + var operation = service.operationDescription("SecondaryActivate"); + operation.x = pos.x; + + operation.y = pos.y; + service.startOperationCall(operation); + taskIcon.activated() + break; + } + } + + function openContextMenu(pos) { + var service = model.Service; + var operation = service.operationDescription("ContextMenu"); + operation.x = pos.x; + operation.y = pos.y; + + var job = service.startOperationCall(operation); + job.finished.connect(function () { + plasmoid.nativeInterface.showStatusNotifierContextMenu(job, taskIcon); + }); + } + + onWheel: { + //don't send activateVertScroll with a delta of 0, some clients seem to break (kmix) + if (wheel.angleDelta.y !== 0) { + var service = model.Service; + var operation = service.operationDescription("Scroll"); + operation.delta =wheel.angleDelta.y; + operation.direction = "Vertical"; + service.startOperationCall(operation); + } + if (wheel.angleDelta.x !== 0) { + var service = model.Service; + var operation = service.operationDescription("Scroll"); + operation.delta =wheel.angleDelta.x; + operation.direction = "Horizontal"; + service.startOperationCall(operation); + } + } +} diff --git a/Plasma Widgets/System Tray/contents/ui/main.qml b/Plasma Widgets/System Tray/contents/ui/main.qml new file mode 100644 index 0000000..e284732 --- /dev/null +++ b/Plasma Widgets/System Tray/contents/ui/main.qml @@ -0,0 +1,238 @@ +/* + * Copyright 2011 Marco Martin + * Copyright 2020 Konrad Materka + * + * 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 Library 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.5 +import QtQuick.Layouts 1.1 +import org.kde.plasma.core 2.1 as PlasmaCore +import org.kde.plasma.plasmoid 2.0 +import org.kde.draganddrop 2.0 as DnD +import org.kde.kirigami 2.5 as Kirigami + +import "items" + +MouseArea { + id: root + + readonly property bool vertical: plasmoid.formFactor === PlasmaCore.Types.Vertical + + Layout.minimumWidth: vertical ? PlasmaCore.Units.iconSizes.small : mainLayout.implicitWidth + PlasmaCore.Units.smallSpacing + Layout.minimumHeight: vertical ? mainLayout.implicitHeight + PlasmaCore.Units.smallSpacing : PlasmaCore.Units.iconSizes.small + + LayoutMirroring.enabled: !vertical && Qt.application.layoutDirection === Qt.RightToLeft + LayoutMirroring.childrenInherit: true + + readonly property alias systemTrayState: systemTrayState + readonly property alias itemSize: tasksGrid.itemSize + readonly property alias visibleLayout: tasksGrid + readonly property alias hiddenLayout: expandedRepresentation.hiddenLayout + + onWheel: { + // Don't propagate unhandled wheel events + wheel.accepted = true; + } + + SystemTrayState { + id: systemTrayState + } + + //being there forces the items to fully load, and they will be reparented in the popup one by one, this item is *never* visible + Item { + id: preloadedStorage + visible: false + } + + CurrentItemHighLight { + location: plasmoid.location + parent: root + } + + DnD.DropArea { + anchors.fill: parent + + preventStealing: true; + + /** Extracts the name of the system tray applet in the drag data if present + * otherwise returns null*/ + function systemTrayAppletName(event) { + if (event.mimeData.formats.indexOf("text/x-plasmoidservicename") < 0) { + return null; + } + var plasmoidId = event.mimeData.getDataAsByteArray("text/x-plasmoidservicename"); + + if (!plasmoid.nativeInterface.isSystemTrayApplet(plasmoidId)) { + return null; + } + return plasmoidId; + } + + onDragEnter: { + if (!systemTrayAppletName(event)) { + event.ignore(); + } + } + + onDrop: { + var plasmoidId = systemTrayAppletName(event); + if (!plasmoidId) { + event.ignore(); + return; + } + + if (plasmoid.configuration.extraItems.indexOf(plasmoidId) < 0) { + var extraItems = plasmoid.configuration.extraItems; + extraItems.push(plasmoidId); + plasmoid.configuration.extraItems = extraItems; + } + } + } + + //Main Layout + GridLayout { + id: mainLayout + + rowSpacing: 0 + columnSpacing: 0 + anchors.fill: parent + + flow: vertical ? GridLayout.TopToBottom : GridLayout.LeftToRight + + GridView { + id: tasksGrid + + Layout.alignment: Qt.AlignCenter + + interactive: false //disable features we don't need + flow: vertical ? GridView.LeftToRight : GridView.TopToBottom + + // The icon size to display when not using the auto-scaling setting + readonly property int smallIconSize: PlasmaCore.Units.iconSizes.smallMedium + readonly property bool autoSize: plasmoid.configuration.scaleIconsToFit + + readonly property int gridThickness: root.vertical ? root.width : root.height + // Should change to 2 rows/columns on a 56px panel (in standard DPI) + readonly property int rowsOrColumns: autoSize ? 1 : Math.max(1, Math.min(count, Math.floor(gridThickness / (smallIconSize + PlasmaCore.Units.smallSpacing)))) + + // Add margins only if the panel is larger than a small icon (to avoid large gaps between tiny icons) + readonly property int smallSizeCellLength: gridThickness < smallIconSize ? smallIconSize : smallIconSize + PlasmaCore.Units.smallSpacing * 2 + cellHeight: { + if (root.vertical) { + return autoSize ? root.width + PlasmaCore.Units.smallSpacing : smallSizeCellLength + } else { + return autoSize ? root.height : Math.floor(root.height / rowsOrColumns) + } + } + cellWidth: { + if (root.vertical) { + return autoSize ? root.width : Math.floor(root.width / rowsOrColumns) + } else { + return autoSize ? root.height + PlasmaCore.Units.smallSpacing : smallSizeCellLength + } + } + + //depending on the form factor, we are calculating only one dimention, second is always the same as root/parent + implicitHeight: root.vertical ? cellHeight * Math.ceil(count / rowsOrColumns) : root.height + implicitWidth: !root.vertical ? cellWidth * Math.ceil(count / rowsOrColumns) : root.width + + // Used only by AbstractItem, but it's easiest to keep it here since it + // uses dimensions from this item to calculate the final value + readonly property int itemSize: { + if (autoSize) { + const size = Math.min(implicitWidth / rowsOrColumns, implicitHeight / rowsOrColumns) + return PlasmaCore.Units.roundToIconSize(Math.min(size, PlasmaCore.Units.iconSizes.enormous)) + } else { + return smallIconSize + } + } + + model: PlasmaCore.SortFilterModel { + sourceModel: plasmoid.nativeInterface.systemTrayModel + filterRole: "effectiveStatus" + filterCallback: function(source_row, value) { + return value === PlasmaCore.Types.ActiveStatus + } + } + + delegate: ItemLoader {} + + add: Transition { + enabled: itemSize > 0 + + NumberAnimation { + property: "scale" + from: 0 + to: 1 + easing.type: Easing.InOutQuad + duration: PlasmaCore.Units.longDuration + } + } + + displaced: Transition { + //ensure scale value returns to 1.0 + //https://doc.qt.io/qt-5/qml-qtquick-viewtransition.html#handling-interrupted-animations + NumberAnimation { + property: "scale" + to: 1 + easing.type: Easing.InOutQuad + duration: PlasmaCore.Units.longDuration + } + } + + move: Transition { + NumberAnimation { + properties: "x,y" + easing.type: Easing.InOutQuad + duration: PlasmaCore.Units.longDuration + } + } + } + + ExpanderArrow { + id: expander + Layout.fillWidth: vertical + Layout.fillHeight: !vertical + Layout.alignment: vertical ? Qt.AlignVCenter : Qt.AlignHCenter + visible: root.hiddenLayout.itemCount > 0 + } + } + + //Main popup + PlasmaCore.Dialog { + id: dialog + visualParent: root + flags: Qt.WindowStaysOnTopHint + location: plasmoid.location + hideOnWindowDeactivate: !plasmoid.configuration.pin + visible: systemTrayState.expanded + + onVisibleChanged: { + systemTrayState.expanded = visible + } + mainItem: ExpandedRepresentation { + id: expandedRepresentation + + Keys.onEscapePressed: { + systemTrayState.expanded = false + } + + LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft + LayoutMirroring.childrenInherit: true + } + } +} diff --git a/Plasma Widgets/System Tray/metadata.desktop b/Plasma Widgets/System Tray/metadata.desktop new file mode 100644 index 0000000..408860a --- /dev/null +++ b/Plasma Widgets/System Tray/metadata.desktop @@ -0,0 +1,108 @@ +[Desktop Entry] +Name=System Tray +Name[af]=Stelsellaai +Name[ar]=صينية النظام +Name[ast]=Bandexa del sistema +Name[az]=Sistem Çəkməcəsi +Name[be]=Сістэмны трэй +Name[be@latin]=Systemny trej +Name[bg]=Системен панел +Name[bn]=সিস্টেম ট্রে +Name[bn_IN]=সিস্টেম ট্রে +Name[br]=Barlenn ar reizhiad +Name[bs]=Sistemska kaseta +Name[ca]=Safata del sistema +Name[ca@valencia]=Safata del sistema +Name[cs]=Systémová část panelu +Name[csb]=Systemòwi zabiérnik +Name[cy]=Bar Tasgau +Name[da]=Statusområde +Name[de]=Systemabschnitt der Kontrollleiste +Name[el]=Πλαίσιο συστήματος +Name[en_GB]=System Tray +Name[eo]=Sistempleto +Name[es]=Bandeja del sistema +Name[et]=Süsteemne dokk +Name[eu]=Sistema-erretilua +Name[fa]=سینی سیستم +Name[fi]=Ilmoitusalue +Name[fr]=Boîte à miniatures +Name[fy]=Systeemfak +Name[ga]=Tráidire an Chórais +Name[gl]=Bandexa do sistema +Name[gu]=સિસ્ટમ ટ્રે +Name[he]=מגש המערכת +Name[hi]=तंत्र तश्तरी +Name[hne]=तंत्र तस्तरी +Name[hr]=Sistemski blok +Name[hsb]=Systemowa wotkładka +Name[hu]=Paneltálca +Name[ia]=Tabuliero de systema +Name[id]=System Tray +Name[is]=Kerfisbakki +Name[it]=Vassoio di sistema +Name[ja]=システムトレイ +Name[ka]=სისტემური პანელი +Name[kk]=Жүйелік сөре +Name[km]=ថាស​ប្រព័ន្ធ +Name[kn]=ವ್ಯವಸ್ಥಾ ಖಾನೆ (ಟ್ರೇ) +Name[ko]=시스템 트레이 +Name[lt]=Sistemos dėklas +Name[lv]=Sistēmas ikonu josla +Name[mai]=तंत्र तश्तरी +Name[mk]=Системска лента +Name[ml]=സിസ്റ്റം ട്രേ +Name[mr]=प्रणाली ट्रे +Name[ms]=Dulang Sistem +Name[nb]=Systemkurv +Name[nds]=Paneel-Systeemafsnitt +Name[ne]=प्रणाली ट्रे +Name[nl]=Systeemvak +Name[nn]=Systemtrau +Name[or]=ତନ୍ତ୍ର ଧାରକ +Name[pa]=ਸਿਸਟਮ ਟਰੇ +Name[pl]=Tacka systemowa +Name[pt]=Bandeja do Sistema +Name[pt_BR]=Área de notificação +Name[ro]=Tavă de sistem +Name[ru]=Системный лоток +Name[se]=Vuogádatgárcu +Name[si]=පද්ධතිය තැටිය +Name[sk]=Systémová lišta +Name[sl]=Sistemska vrstica +Name[sr]=системска касета +Name[sr@ijekavian]=системска касета +Name[sr@ijekavianlatin]=sistemska kaseta +Name[sr@latin]=sistemska kaseta +Name[sv]=Systembricka +Name[ta]=சாதனத் தட்டு +Name[te]=వ్యవస్థ ట్రె +Name[tg]=Лавҳачаи низомӣ +Name[th]=ถาดระบบ +Name[tr]=Sistem Çekmecesi +Name[ug]=سىستېما قوندىقى +Name[uk]=Системний лоток +Name[vi]=Khay hệ thống +Name[wa]=Boesse ås imådjetes sistinme +Name[xh]=Itreyi Yendlela yokusebenza +Name[x-test]=xxSystem Trayxx +Name[zh_CN]=系统托盘 +Name[zh_TW]=系統匣 +Icon=preferences-desktop-notification +Type=Service +X-KDE-ServiceTypes=Plasma/Applet,Plasma/Containment + +X-Plasma-API=declarativeappletscript +X-Plasma-MainScript=ui/main.qml +X-KDE-PluginInfo-Author=Marco Martin +X-KDE-PluginInfo-Email=mart@kde.org +X-KDE-PluginInfo-Name=org.kde.plasma.private.systemtray +X-KDE-PluginInfo-Version=1.0 +X-KDE-PluginInfo-Website=https://www.kde.org/plasma-desktop +X-KDE-PluginInfo-Category=Windows and Tasks +X-KDE-PluginInfo-License=GPL-2.0+ +X-KDE-PluginInfo-EnabledByDefault=true +X-Plasma-ContainmentType=Panel +#this is the internal implementation: can't be loaded directly +NoDisplay=true +X-KDE-FormFactors=desktop diff --git a/Plasma Widgets/System Tray/metadata.json b/Plasma Widgets/System Tray/metadata.json new file mode 100644 index 0000000..cd635b0 --- /dev/null +++ b/Plasma Widgets/System Tray/metadata.json @@ -0,0 +1,117 @@ +{ + "KPlugin": { + "Authors": [ + { + "Email": "mart@kde.org", + "Name": "Marco Martin" + } + ], + "Category": "Windows and Tasks", + "EnabledByDefault": true, + "FormFactors": [ + "desktop" + ], + "Icon": "preferences-desktop-notification", + "Id": "org.kde.plasma.private.systemtray", + "License": "GPL-2.0+", + "Name": "System Tray", + "Name[af]": "Stelsellaai", + "Name[ar]": "صينية النظام", + "Name[ast]": "Bandexa del sistema", + "Name[az]": "Sistem Çəkməcəsi", + "Name[be@latin]": "Systemny trej", + "Name[be]": "Сістэмны трэй", + "Name[bg]": "Системен панел", + "Name[bn]": "সিস্টেম ট্রে", + "Name[bn_IN]": "সিস্টেম ট্রে", + "Name[br]": "Barlenn ar reizhiad", + "Name[bs]": "Sistemska kaseta", + "Name[ca@valencia]": "Safata del sistema", + "Name[ca]": "Safata del sistema", + "Name[cs]": "Systémová část panelu", + "Name[csb]": "Systemòwi zabiérnik", + "Name[cy]": "Bar Tasgau", + "Name[da]": "Statusområde", + "Name[de]": "Systemabschnitt der Kontrollleiste", + "Name[el]": "Πλαίσιο συστήματος", + "Name[en_GB]": "System Tray", + "Name[eo]": "Sistempleto", + "Name[es]": "Bandeja del sistema", + "Name[et]": "Süsteemne dokk", + "Name[eu]": "Sistema-erretilua", + "Name[fa]": "سینی سیستم", + "Name[fi]": "Ilmoitusalue", + "Name[fr]": "Boîte à miniatures", + "Name[fy]": "Systeemfak", + "Name[ga]": "Tráidire an Chórais", + "Name[gl]": "Bandexa do sistema", + "Name[gu]": "સિસ્ટમ ટ્રે", + "Name[he]": "מגש המערכת", + "Name[hi]": "तंत्र तश्तरी", + "Name[hne]": "तंत्र तस्तरी", + "Name[hr]": "Sistemski blok", + "Name[hsb]": "Systemowa wotkładka", + "Name[hu]": "Paneltálca", + "Name[ia]": "Tabuliero de systema", + "Name[id]": "System Tray", + "Name[is]": "Kerfisbakki", + "Name[it]": "Vassoio di sistema", + "Name[ja]": "システムトレイ", + "Name[ka]": "სისტემური პანელი", + "Name[kk]": "Жүйелік сөре", + "Name[km]": "ថាស​ប្រព័ន្ធ", + "Name[kn]": "ವ್ಯವಸ್ಥಾ ಖಾನೆ (ಟ್ರೇ)", + "Name[ko]": "시스템 트레이", + "Name[lt]": "Sistemos dėklas", + "Name[lv]": "Sistēmas ikonu josla", + "Name[mai]": "तंत्र तश्तरी", + "Name[mk]": "Системска лента", + "Name[ml]": "സിസ്റ്റം ട്രേ", + "Name[mr]": "प्रणाली ट्रे", + "Name[ms]": "Dulang Sistem", + "Name[nb]": "Systemkurv", + "Name[nds]": "Paneel-Systeemafsnitt", + "Name[ne]": "प्रणाली ट्रे", + "Name[nl]": "Systeemvak", + "Name[nn]": "Systemtrau", + "Name[or]": "ତନ୍ତ୍ର ଧାରକ", + "Name[pa]": "ਸਿਸਟਮ ਟਰੇ", + "Name[pl]": "Tacka systemowa", + "Name[pt]": "Bandeja do Sistema", + "Name[pt_BR]": "Área de notificação", + "Name[ro]": "Tavă de sistem", + "Name[ru]": "Системный лоток", + "Name[se]": "Vuogádatgárcu", + "Name[si]": "පද්ධතිය තැටිය", + "Name[sk]": "Systémová lišta", + "Name[sl]": "Sistemska vrstica", + "Name[sr@ijekavian]": "системска касета", + "Name[sr@ijekavianlatin]": "sistemska kaseta", + "Name[sr@latin]": "sistemska kaseta", + "Name[sr]": "системска касета", + "Name[sv]": "Systembricka", + "Name[ta]": "சாதனத் தட்டு", + "Name[te]": "వ్యవస్థ ట్రె", + "Name[tg]": "Лавҳачаи низомӣ", + "Name[th]": "ถาดระบบ", + "Name[tr]": "Sistem Çekmecesi", + "Name[ug]": "سىستېما قوندىقى", + "Name[uk]": "Системний лоток", + "Name[vi]": "Khay hệ thống", + "Name[wa]": "Boesse ås imådjetes sistinme", + "Name[x-test]": "xxSystem Trayxx", + "Name[xh]": "Itreyi Yendlela yokusebenza", + "Name[zh_CN]": "系统托盘", + "Name[zh_TW]": "系統匣", + "ServiceTypes": [ + "Plasma/Applet", + "Plasma/Containment" + ], + "Version": "1.0", + "Website": "https://www.kde.org/plasma-desktop" + }, + "NoDisplay": true, + "X-Plasma-API": "declarativeappletscript", + "X-Plasma-ContainmentType": "Panel", + "X-Plasma-MainScript": "ui/main.qml" +} diff --git a/README.md b/README.md index d80bd9f..0fb6b19 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,10 @@ there are any improvements to be made here, any and all effort would be greatly +### System Tray + + + ### Plasma Style @@ -272,6 +276,16 @@ or inconsistencies, for now post them in the next desktop threads. Make sure that your panel's width is set to 40. Also make sure that you're using the ```Icons-only Task Manager``` widget to make it look closer to Windows 7. +#### Modified System Tray + +This modification will add hover animations to the default system tray plasmoid, as well as remove the annoying popup animation which happens upon clicking on an item. +Since the system tray is a complex plasmoid, its files have to be replaced with a modified version provided in this theme. To do this, copy the ```org.kde.plasma.private.systemtray``` found in the ```Plasma Widgets``` folder to the following directory: + +```/usr/share/plasma/plasmoids/``` + +This will override the default System Tray plasmoid. It is not recommended to edit this particular plasmoid, so proceed with caution. Make sure to back up the original plasmoid somewhere safe. + + #### Digital Clock Lite Install the widget ```Digital Clock Lite``` (https://www.kde-look.org/p/1225135/) and replace the ugly large clock widget with @@ -282,6 +296,8 @@ it. By default it should already look a lot like Windows 7's clock, but if it do You can tweak the other settings to your liking. +#### Show Desktop (Win7) + Lastly, install the ```Show Desktop (Win7)``` widget (https://www.kde-look.org/p/1100895/) and configure it to these settings: In Look: diff --git a/Screenshots/System_Tray.png b/Screenshots/System_Tray.png new file mode 100644 index 0000000..bccc892 Binary files /dev/null and b/Screenshots/System_Tray.png differ