plasmoides KDE Store/GitHub (gnome-pager, kMenu, kvitals, windowtitle, claude, launchpad)

This commit is contained in:
Josevi
2026-07-08 20:47:59 +02:00
parent ca606377ee
commit dd3b0f6ae8
136 changed files with 20239 additions and 0 deletions
@@ -0,0 +1,122 @@
/*
SPDX-FileCopyrightText: 2013 Aurélien Gâteau <agateau@kde.org>
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.extras 2.0 as PlasmaExtras
Item {
id: root
property QtObject menu
property Item visualParent
property variant actionList
property bool opened: menu ? (menu.status !== PlasmaExtras.Menu.Closed) : false
signal actionClicked(string actionId, variant actionArgument)
signal closed
onActionListChanged: refreshMenu();
onOpenedChanged: {
if (!opened) {
closed();
}
}
function open(x, y) {
if (!actionList) {
return;
}
if (x && y) {
menu.open(x, y);
} else {
menu.open();
}
}
function refreshMenu() {
if (menu) {
menu.destroy();
}
if (!actionList) {
return;
}
menu = contextMenuComponent.createObject(root);
fillMenu(menu, actionList);
}
function fillMenu(menu, items) {
items.forEach(function(actionItem) {
if (actionItem.subActions) {
// This is a menu
var submenuItem = contextSubmenuItemComponent.createObject(
menu, { "actionItem" : actionItem });
fillMenu(submenuItem.submenu, actionItem.subActions);
} else {
var item = contextMenuItemComponent.createObject(
menu,
{
"actionItem": actionItem,
}
);
}
});
}
Component {
id: contextMenuComponent
PlasmaExtras.Menu {
visualParent: root.visualParent
}
}
Component {
id: contextSubmenuItemComponent
PlasmaExtras.MenuItem {
id: submenuItem
property variant actionItem
text: actionItem.text ? actionItem.text : ""
icon: actionItem.icon ? actionItem.icon : null
property PlasmaExtras.Menu submenu: PlasmaExtras.Menu {
visualParent: submenuItem.action
}
}
}
Component {
id: contextMenuItemComponent
PlasmaExtras.MenuItem {
property variant actionItem
text : actionItem.text ? actionItem.text : ""
enabled : actionItem.type !== "title" && ("enabled" in actionItem ? actionItem.enabled : true)
separator : actionItem.type === "separator"
section : actionItem.type === "title"
icon : actionItem.icon ? actionItem.icon : null
checkable : actionItem.checkable ? actionItem.checkable : false
checked : actionItem.checked ? actionItem.checked : false
onClicked: {
root.actionClicked(actionItem.actionId, actionItem.actionArgument);
}
}
}
}
@@ -0,0 +1,119 @@
/*
SPDX-FileCopyrightText: 2013-2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.private.kicker 0.1 as Kicker
Item {
id: root
readonly property bool vertical: (Plasmoid.formFactor === PlasmaCore.Types.Vertical)
readonly property bool useCustomButtonImage: (Plasmoid.configuration.useCustomButtonImage
&& Plasmoid.configuration.customButtonImage.length !== 0)
readonly property Component dashWindowComponent: kicker.isDash ? Qt.createComponent(Qt.resolvedUrl("./DashboardRepresentation.qml"), root) : null
readonly property Kicker.DashboardWindow dashWindow: dashWindowComponent && dashWindowComponent.status === Component.Ready
? dashWindowComponent.createObject(root, { visualParent: root }) : null
onWidthChanged: updateSizeHints()
onHeightChanged: updateSizeHints()
function updateSizeHints() {
if (useCustomButtonImage) {
if (vertical) {
const scaledHeight = Math.floor(parent.width * (buttonIcon.implicitHeight / buttonIcon.implicitWidth));
root.Layout.minimumWidth = -1;
root.Layout.minimumHeight = scaledHeight;
root.Layout.maximumWidth = Kirigami.Units.iconSizes.huge;
root.Layout.maximumHeight = scaledHeight;
} else {
const scaledWidth = Math.floor(parent.height * (buttonIcon.implicitWidth / buttonIcon.implicitHeight));
root.Layout.minimumWidth = scaledWidth;
root.Layout.minimumHeight = -1;
root.Layout.maximumWidth = scaledWidth;
root.Layout.maximumHeight = Kirigami.Units.iconSizes.huge;
}
} else {
root.Layout.minimumWidth = Kirigami.Units.iconSizes.huge;
root.Layout.minimumHeight = Kirigami.Units.iconSizes.huge;
}
}
Kirigami.Icon {
id: buttonIcon
anchors.fill: parent
readonly property double aspectRatio: root.vertical
? implicitHeight / implicitWidth
: implicitWidth / implicitHeight
active: mouseArea.containsMouse && !justOpenedTimer.running
source: root.useCustomButtonImage ? Plasmoid.configuration.customButtonImage : Plasmoid.configuration.icon
// A custom icon could also be rectangular. However, if a square, custom, icon is given, assume it
// to be an icon and round it to the nearest icon size again to avoid scaling artifacts.
roundToIconSize: !root.useCustomButtonImage || aspectRatio === 1
onSourceChanged: root.updateSizeHints()
}
MouseArea {
id: mouseArea
anchors.fill: parent
property bool wasExpanded: false;
activeFocusOnTab: true
hoverEnabled: !root.dashWindow || !root.dashWindow.visible
Keys.onPressed: {
switch (event.key) {
case Qt.Key_Space:
case Qt.Key_Enter:
case Qt.Key_Return:
case Qt.Key_Select:
Plasmoid.activated();
break;
}
}
Accessible.name: Plasmoid.title
Accessible.description: toolTipSubText
Accessible.role: Accessible.Button
onPressed: {
if (!kicker.isDash) {
wasExpanded = kicker.expanded
}
}
onClicked: {
if (kicker.isDash) {
root.dashWindow.toggle();
justOpenedTimer.start();
} else {
kicker.expanded = !wasExpanded;
}
}
}
Connections {
target: Plasmoid
enabled: kicker.isDash && root.dashWindow !== null
function onActivated() {
root.dashWindow.toggle();
justOpenedTimer.start();
}
}
}
@@ -0,0 +1,239 @@
/*
SPDX-FileCopyrightText: 2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls 2.15
import org.kde.draganddrop 2.0 as DragDrop
import org.kde.kirigami 2.5 as Kirigami
import org.kde.iconthemes as KIconThemes
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.plasmoid 2.0
import org.kde.kcmutils as KCM
KCM.SimpleKCM {
id: configGeneral
property bool isDash: (Plasmoid.pluginName === "org.kde.plasma.kickerdash")
property string cfg_icon: Plasmoid.configuration.icon
property bool cfg_useCustomButtonImage: Plasmoid.configuration.useCustomButtonImage
property string cfg_customButtonImage: Plasmoid.configuration.customButtonImage
property alias cfg_appNameFormat: appNameFormat.currentIndex
property alias cfg_limitDepth: limitDepth.checked
property alias cfg_alphaSort: alphaSort.checked
property alias cfg_showIconsRootLevel: showIconsRootLevel.checked
property alias cfg_recentOrdering: recentOrdering.currentIndex
property alias cfg_showRecentApps: showRecentApps.checked
property alias cfg_showRecentDocs: showRecentDocs.checked
property alias cfg_useExtraRunners: useExtraRunners.checked
property alias cfg_alignResultsToBottom: alignResultsToBottom.checked
property alias cfg_appsIconSize: appsIconSize.currentIndex
property alias cfg_favsIconSize: favsIconSize.currentIndex
property alias cfg_systemIconSize: systemIconSize.currentIndex
Kirigami.FormLayout {
anchors.left: parent.left
anchors.right: parent.right
Button {
id: iconButton
Kirigami.FormData.label: i18n("Icon:")
implicitWidth: previewFrame.width + Kirigami.Units.smallSpacing * 2
implicitHeight: previewFrame.height + Kirigami.Units.smallSpacing * 2
// Just to provide some visual feedback when dragging;
// cannot have checked without checkable enabled
checkable: true
checked: dropArea.containsAcceptableDrag
onPressed: iconMenu.opened ? iconMenu.close() : iconMenu.open()
DragDrop.DropArea {
id: dropArea
property bool containsAcceptableDrag: false
anchors.fill: parent
onDragEnter: {
// Cannot use string operations (e.g. indexOf()) on "url" basic type.
var urlString = event.mimeData.url.toString();
// This list is also hardcoded in KIconDialog.
var extensions = [".png", ".xpm", ".svg", ".svgz"];
containsAcceptableDrag = urlString.indexOf("file:///") === 0 && extensions.some(function (extension) {
return urlString.indexOf(extension) === urlString.length - extension.length; // "endsWith"
});
if (!containsAcceptableDrag) {
event.ignore();
}
}
onDragLeave: containsAcceptableDrag = false
onDrop: {
if (containsAcceptableDrag) {
// Strip file:// prefix, we already verified in onDragEnter that we have only local URLs.
iconDialog.setCustomButtonImage(event.mimeData.url.toString().substr("file://".length));
}
containsAcceptableDrag = false;
}
}
KIconThemes.IconDialog {
id: iconDialog
function setCustomButtonImage(image) {
configGeneral.cfg_customButtonImage = image || configGeneral.cfg_icon || "start-here-kde-symbolic"
configGeneral.cfg_useCustomButtonImage = true;
}
onIconNameChanged: setCustomButtonImage(iconName);
}
KSvg.FrameSvgItem {
id: previewFrame
anchors.centerIn: parent
imagePath: Plasmoid.location === PlasmaCore.Types.Vertical || Plasmoid.location === PlasmaCore.Types.Horizontal
? "widgets/panel-background" : "widgets/background"
width: Kirigami.Units.iconSizes.large + fixedMargins.left + fixedMargins.right
height: Kirigami.Units.iconSizes.large + fixedMargins.top + fixedMargins.bottom
Kirigami.Icon {
anchors.centerIn: parent
width: Kirigami.Units.iconSizes.large
height: width
source: configGeneral.cfg_useCustomButtonImage ? configGeneral.cfg_customButtonImage : configGeneral.cfg_icon
}
}
Menu {
id: iconMenu
// Appear below the button
y: +parent.height
onClosed: iconButton.checked = false;
MenuItem {
text: i18nc("@item:inmenu Open icon chooser dialog", "Choose…")
icon.name: "document-open-folder"
onClicked: iconDialog.open()
}
MenuItem {
text: i18nc("@item:inmenu Reset icon to default", "Clear Icon")
icon.name: "edit-clear"
onClicked: {
configGeneral.cfg_icon = "start-here-kde-symbolic"
configGeneral.cfg_useCustomButtonImage = false
}
}
}
}
Item {
Kirigami.FormData.isSection: true
}
ComboBox {
id: appNameFormat
Kirigami.FormData.label: i18n("Show applications as:")
model: [i18n("Name only"), i18n("Description only"), i18n("Name (Description)"), i18n("Description (Name)")]
}
Item {
Kirigami.FormData.isSection: true
}
CheckBox {
id: alphaSort
visible: false
Kirigami.FormData.label: i18n("Behavior:")
text: i18n("Sort applications alphabetically")
}
CheckBox {
id: limitDepth
visible: false
text: i18n("Flatten sub-menus to a single level")
}
CheckBox {
id: showIconsRootLevel
visible: false
text: i18n("Show icons on the root level of the menu")
}
CheckBox {
id: showRecentApps
visible: false
Kirigami.FormData.label: i18n("Show categories:")
text: recentOrdering.currentIndex == 0
? i18n("Recent applications")
: i18n("Often used applications")
}
CheckBox {
id: showRecentDocs
visible: false
text: recentOrdering.currentIndex == 0
? i18n("Recent files")
: i18n("Often used files")
}
ComboBox {
id: recentOrdering
visible: false
Kirigami.FormData.label: i18n("Sort items in categories by:")
model: [i18nc("@item:inlistbox Sort items in categories by [Recently used | Often used]", "Recently used"), i18nc("@item:inlistbox Sort items in categories by [Recently used | Ofetn used]", "Often used")]
}
CheckBox {
id: useExtraRunners
visible: false
Kirigami.FormData.label: i18n("Search:")
text: i18n("Expand search to bookmarks, files and emails")
}
CheckBox {
id: alignResultsToBottom
visible: false
text: i18n("Align search results to bottom")
}
ComboBox {
id: appsIconSize
Kirigami.FormData.label: i18n("Apps icon size:")
model: [i18n("Small"),i18n("Medium"),i18n("Large"), i18n("Huge"),i18n("HUGE"),i18n("Enormous")]
}
ComboBox {
id: favsIconSize
Kirigami.FormData.label: i18n("Favs icon size:")
model: [i18n("Small"),i18n("Medium"),i18n("Large"), i18n("Huge"),i18n("Enormous")]
}
ComboBox {
id: systemIconSize
Kirigami.FormData.label: i18n("Favs icon size:")
model: [i18n("Small"),i18n("Medium"),i18n("Large"), i18n("Huge"),i18n("Enormous")]
}
}
}
@@ -0,0 +1,523 @@
/*
SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import Qt5Compat.GraphicalEffects
// Deliberately imported after QtQuick to avoid missing restoreMode property in Binding. Fix in Qt 6.
import QtQml 2.15
import org.kde.kquickcontrolsaddons 2.0
import org.kde.kwindowsystem 1.0
import org.kde.plasma.components as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.plasma.core as PlasmaCore
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.private.shell 2.0
import org.kde.kirigami 2.20 as Kirigami
import QtQuick.Layouts 1.1
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.private.kicker 0.1 as Kicker
import QtQuick.Controls
import QtQuick
import Qt5Compat.GraphicalEffects
import "code/tools.js" as Tools
Kicker.DashboardWindow {
id: root
property bool smallScreen: ((Math.floor(width / Kirigami.Units.iconSizes.huge) <= 22) || (Math.floor(height / Kirigami.Units.iconSizes.huge) <= 14))
property int iconSize:{ switch(Plasmoid.configuration.appsIconSize){
case 0: return Kirigami.Units.iconSizes.smallMedium;
case 1: return Kirigami.Units.iconSizes.medium;
case 2: return Kirigami.Units.iconSizes.large;
case 3: return Kirigami.Units.iconSizes.huge;
case 4: return Kirigami.Units.iconSizes.large * 2;
case 5: return Kirigami.Units.iconSizes.enormous;
default: return 64
}
}
property int favsIconSize:{ switch(Plasmoid.configuration.favsIconSize){
case 0: return Kirigami.Units.iconSizes.smallMedium;
case 1: return Kirigami.Units.iconSizes.medium;
case 2: return Kirigami.Units.iconSizes.large;
case 3: return Kirigami.Units.iconSizes.huge;
case 4: return Kirigami.Units.iconSizes.enormous;
default: return 64
}
}
property int systemIconSize:{ switch(Plasmoid.configuration.systemIconSize){
case 0: return Kirigami.Units.iconSizes.smallMedium;
case 1: return Kirigami.Units.iconSizes.medium;
case 2: return Kirigami.Units.iconSizes.large;
case 3: return Kirigami.Units.iconSizes.huge;
case 4: return Kirigami.Units.iconSizes.enormous;
default: return 64
}
}
property int cellSize: iconSize + (2 * Kirigami.Units.iconSizes.sizeForLabels)
+ (2 * Kirigami.Units.largeSpacing)
+ (2 * Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom,
highlightItemSvg.margins.left + highlightItemSvg.margins.right))
//property int columns: Math.floor(width*0.7/root.cellSize)// Math.floor(((smallScreen ? 85 : 80)/100) * Math.ceil(width / cellSize))
property int columns: Math.floor(((smallScreen ? 85 : 80)/100) * Math.ceil(width / cellSize))
property bool searching: searchField.text !== ""
property int favoritesRows: Math.floor(height*0.4/cellSize)
//keyEventProxy: searchField
backgroundColor: "transparent"
onKeyEscapePressed: {
if (searching) {
searchField.clear();
} else {
root.toggle();
}
}
onVisibleChanged: {
if(visible){
animatorMainColumn.start()
}else{
rootItem.opacity = 0
}
reset();
}
onSearchingChanged: {
if (!searching) {
//mainView.currentIndex = 1
mainView.pop()
reset();
} else {
mainView.push(runnerComponent)
//mainView.currentIndex = 0
}
}
function colorWithAlpha(color: color, alpha: real): color {
return Qt.rgba(color.r, color.g, color.b, alpha)
}
function reset() {
allAppsGrid.model = rootModel.modelForRow(2)
globalFavoritesGrid.model = globalFavorites
allAppsGrid.currentIndex = -1
globalFavoritesGrid.currentIndex = -1;
systemFavoritesGrid.currentIndex = -1;
allAppsGrid.forceLayout()
searchField.clear();
searchField.focus = true
}
mainItem: MouseArea {
id: rootItem
anchors.fill: parent
acceptedButtons: Qt.LeftButton | Qt.RightButton
LayoutMirroring.enabled: Qt.application.layoutDirection === Qt.RightToLeft
LayoutMirroring.childrenInherit: true
Rectangle{
anchors.fill: parent
color: Kirigami.Theme.backgroundColor
opacity: 0.4
}
Connections {
target: kicker
function onReset() {
if (!root.searching) {
//filterList.applyFilter();
//funnelModel.reset();
}
}
function onDragSourceChanged() {
if (!kicker.dragSource) {
// FIXME TODO HACK: Reset all views post-DND to work around
// mouse grab bug despite QQuickWindow::mouseGrabberItem==0x0.
// Needs a more involved hunt through Qt Quick sources later since
// it's not happening with near-identical code in the menu repr.
rootModel.refresh();
}
}
}
Connections {
target: Plasmoid
function onUserConfiguringChanged() {
if (Plasmoid.userConfiguring) {
root.hide()
}
}
}
PlasmaExtras.Menu {
id: contextMenu
PlasmaExtras.MenuItem {
action: Plasmoid.internalAction("configure")
}
}
Kirigami.Heading {
id: dummyHeading
visible: false
width: 0
level: 1
}
TextMetrics {
id: headingMetrics
font: dummyHeading.font
}
Kicker.FunnelModel {
id: funnelModel
onSourceModelChanged: {
if (mainColumn.visible) {
mainGrid.currentIndex = -1;
mainGrid.forceLayout();
}
}
}
Kicker.ContainmentInterface {
id: containmentInterface
}
TextField{
id: searchField
anchors.horizontalCenter: parent.horizontalCenter
anchors.bottom: mainView.top
anchors.bottomMargin: Kirigami.Units.largeSpacing * 6
//focus: true
width: Kirigami.Units.gridUnit * 13
topPadding: Kirigami.Units.largeSpacing
bottomPadding: Kirigami.Units.largeSpacing
placeholderText: i18nc("@info:placeholder as in, 'start typing to initiate a search'", "Search")
horizontalAlignment: TextInput.AlignHCenter
wrapMode: Text.NoWrap
font.pointSize: Kirigami.Theme.defaultFont.pointSize + 0.5
onTextChanged: {
runnerModel.query = searchField.text;
}
function clear() {
text = "";
}
background: Rectangle {
color: colorWithAlpha(Kirigami.Theme.backgroundColor,0.7)
radius: 100
border.width: 1
border.color: colorWithAlpha(Kirigami.Theme.textColor,0.05)
}
function appendText(newText) {
if (!root.visible) {
return;
}
focus = true;
text = text + newText;
}
function backspace() {
if (!root.visible) {
return;
}
focus = true;
text = text.slice(0, -1);
}
function updateSelection() {
if (!searchField.selectedText) {
return;
}
var delta = text.lastIndexOf(searchField.text, text.length - 2);
searchHeading.select(searchField.selectionStart + delta, searchField.selectionEnd + delta);
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Down || event.key === Qt.Key_Tab) {
event.accepted = true;
if(root.searching){
mainView.currentItem.tryActivate(0,0)
mainView.currentItem.forceActiveFocus()
}
else{
allAppsGrid.tryActivate(0,0)
allAppsGrid.forceActiveFocus()
}
}
}
}
OpacityAnimator{ id: animatorMainColumn ;from: 0; to: 1 ; target: rootItem;}
StackView {
id: mainView
width: (root.columns * root.cellSize) + Kirigami.Units.gridUnit
height: Math.ceil(root.height*0.7/root.cellSize) * root.cellSize
anchors{
horizontalCenter: parent.horizontalCenter
verticalCenter: parent.verticalCenter
}
initialItem: Column {
id: allAppsColumn
clip: true
spacing: Kirigami.Units.largeSpacing * 2
ItemGridView {
id: allAppsGrid
width: parent.width
height: Math.ceil(root.height*0.7/cellHeight) * cellHeight
cellWidth: root.cellSize
cellHeight: root.cellSize
iconSize: root.iconSize
dropEnabled: false
onKeyNavDown: {
allAppsGrid.focus = false
globalFavoritesGrid.tryActivate(0,0)
globalFavoritesGrid.forceActiveFocus()
}
onKeyNavUp: {
allAppsGrid.focus = false
searchField.focus = true
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Tab) {
event.accepted = true;
allAppsGrid.focus = false
globalFavoritesGrid.tryActivate(0,0)
globalFavoritesGrid.forceActiveFocus()
}
}
}
}
pushEnter: Transition {
PropertyAnimation {
property: "opacity"
from: 0
to:1
duration: 200
}
}
pushExit: Transition {
PropertyAnimation {
property: "opacity"
from: 1
to:0
duration: 200
}
}
popEnter: Transition {
PropertyAnimation {
property: "opacity"
from: 0
to:1
duration: 200
}
}
popExit: Transition {
PropertyAnimation {
property: "opacity"
from: 1
to:0
duration: 200
}
}
}
Component {
id: runnerComponent
ItemGridView {
id: runnerGrid
anchors.horizontalCenter: mainView.horizontalCenter
width: mainView.width/2
clip: true
height: mainView.height
grabFocus: true
cellWidth: root.cellSize
cellHeight: root.cellSize
iconSize: root.iconSize
model: runnerModel.count > 0 ? runnerModel.modelForRow(0) : undefined
onKeyNavDown: {
runnerGrid.focus = false
globalFavoritesGrid.tryActivate(0,0)
globalFavoritesGrid.forceActiveFocus()
}
onKeyNavUp: {
runnerGrid.focus = false
searchField.focus = true
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Tab) {
event.accepted = true;
runnerGrid.focus = false
globalFavoritesGrid.tryActivate(0,0)
globalFavoritesGrid.forceActiveFocus()
}
}
}
}
Rectangle{
anchors.centerIn: globalFavoritesGrid
height: globalFavoritesGrid.height + Kirigami.Units.largeSpacing
width: globalFavoritesGrid.width + Kirigami.Units.largeSpacing
color: Kirigami.Theme.backgroundColor
radius: 10
opacity: 0.6
z:1
}
ItemGridView {
id: globalFavoritesGrid
width: globalFavoritesGrid.model ? Math.min(Math.floor((root.width*0.85)/cellWidth)*cellWidth,globalFavoritesGrid.model.count*cellWidth) : 0
iconSize: root.favsIconSize
cellHeight: iconSize + Kirigami.Units.largeSpacing
cellWidth: cellHeight + Kirigami.Units.largeSpacing
clip: true
z:2
verticalScrollBarPolicy: PlasmaComponents.ScrollBar.AlwaysOff
height: cellHeight
anchors.bottom: parent.bottom
anchors.bottomMargin: Kirigami.Units.largeSpacing
anchors.horizontalCenter: parent.horizontalCenter
showLabels: false
dropEnabled: true
dragEnabled: true
onKeyNavUp: {
if(root.searching){
globalFavoritesGrid.focus = false
//runnerGrid.tryActivate(0,0)
//runnerGrid.forceActiveFocus()
mainView.currentItem.tryActivate(0,0)
mainView.currentItem.forceActiveFocus()
}
else{
globalFavoritesGrid.focus = false
allAppsGrid.tryActivate(0,0)
allAppsGrid.forceActiveFocus()
}
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Tab) {
event.accepted = true;
globalFavoritesGrid.focus = false
systemFavoritesGrid.tryActivate(0,0)
systemFavoritesGrid.forceActiveFocus()
}
}
}
ItemGridView {
id: systemFavoritesGrid
anchors.top: parent.top
anchors.right: parent.right
clip: true
width: cellWidth
height: systemFavoritesGrid.model ? systemFavoritesGrid.model.count * cellHeight : 0
cellWidth: iconSize + Kirigami.Units.largeSpacing * 2
cellHeight: cellWidth
iconSize: root.systemIconSize
z:5
showLabels: false
model: systemFavorites
dragEnabled: false
dropEnabled: false
Keys.onPressed: event => {
if (event.key === Qt.Key_Tab) {
event.accepted = true;
systemFavoritesGrid.focus = false
searchField.focus = true
}
}
}
onPressed: mouse => {
if (mouse.button === Qt.RightButton) {
contextMenu.open(mouse.x, mouse.y);
}
}
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
root.toggle();
}
}
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);
}
//searchField.focus = true
}
}
Component.onCompleted: {
rootModel.refresh();
searchField.forceActiveFocus()
}
}
@@ -0,0 +1,120 @@
/*
SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami 2.20 as Kirigami
import "code/tools.js" as Tools
Item {
id: item
width: GridView.view.cellWidth
height: GridView.view.cellHeight
enabled: !model.disabled
property bool showLabel: true
property int itemIndex: model.index
property string favoriteId: model.favoriteId !== undefined ? model.favoriteId : ""
property url url: model.url !== undefined ? model.url : ""
property variant icon: model.decoration !== undefined ? model.decoration : ""
property var m: model
property bool hasActionList: ((model.favoriteId !== null)
|| (("hasActionList" in model) && (model.hasActionList === true)))
Accessible.role: Accessible.MenuItem
Accessible.name: model.display
function openActionMenu(x, y) {
var actionList = hasActionList ? model.actionList : [];
Tools.fillActionMenu(i18n, actionMenu, actionList, GridView.view.model.favoritesModel, model.favoriteId);
actionMenu.visualParent = item;
actionMenu.open(x, y);
}
function actionTriggered(actionId, actionArgument) {
var close = (Tools.triggerAction(GridView.view.model, model.index, actionId, actionArgument) === true);
if (close) {
root.toggle();
}
}
Kirigami.Icon {
id: icon
y: item.showLabel ? (2 * highlightItemSvg.margins.top) : null
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: item.showLabel ? undefined : parent.verticalCenter
width: iconSize
height: width
animated: false
source: model.decoration
}
PlasmaComponents3.Label {
id: label
visible: item.showLabel
anchors {
top: icon.bottom
topMargin: Kirigami.Units.smallSpacing
left: parent.left
leftMargin: highlightItemSvg.margins.left
right: parent.right
rightMargin: highlightItemSvg.margins.right
}
horizontalAlignment: Text.AlignHCenter
maximumLineCount: 2
elide: Text.ElideMiddle
wrapMode: Text.Wrap
font.pointSize: Kirigami.Theme.defaultFont.pointSize + 0.5
text: ("name" in model ? model.name : model.display)
textFormat: Text.PlainText
}
PlasmaCore.ToolTipArea {
id: toolTip
property string text: model.display
anchors.fill: parent
//active: root.visible &&
active: root.visible && ( !item.showLabel || label.truncated)
mainItem: toolTipDelegate
onContainsMouseChanged: item.GridView.view.itemContainsMouseChanged(containsMouse)
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Menu && hasActionList) {
event.accepted = true;
openActionMenu(item);
} else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) {
event.accepted = true;
if ("trigger" in GridView.view.model) {
GridView.view.model.trigger(index, "", null);
root.toggle();
}
itemGrid.itemActivated(index, "", null);
}
}
}
@@ -0,0 +1,472 @@
/*
SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls
import org.kde.kquickcontrolsaddons 2.0
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
FocusScope {
id: itemGrid
signal keyNavLeft
signal keyNavRight
signal keyNavUp
signal keyNavDown
signal itemActivated(int index, string actionId, string argument)
property bool dragEnabled: true
property bool dropEnabled: false
property bool showLabels: true
property bool grabFocus: false
property alias currentIndex: gridView.currentIndex
property alias currentItem: gridView.currentItem
property alias contentItem: gridView.contentItem
property alias count: gridView.count
property alias model: gridView.model
property alias verticalLayoutDirection : gridView.verticalLayoutDirection
property alias cellWidth: gridView.cellWidth
property alias cellHeight: gridView.cellHeight
property alias iconSize: gridView.iconSize
property var horizontalScrollBarPolicy: PlasmaComponents.ScrollBar.AlwaysOff
property var verticalScrollBarPolicy: PlasmaComponents.ScrollBar.AsNeeded
onDropEnabledChanged: {
if (!dropEnabled && "dropPlaceHolderIndex" in model) {
model.dropPlaceHolderIndex = -1;
}
}
onFocusChanged: {
// if (!focus && !root.keyEventProxy.activeFocus) {
if (!focus) {
currentIndex = -1;
}
}
function currentRow() {
if (currentIndex === -1) {
return -1;
}
return Math.floor(currentIndex / Math.floor(width / itemGrid.cellWidth));
}
function currentCol() {
if (currentIndex === -1) {
return -1;
}
return currentIndex - (currentRow() * Math.floor(width / itemGrid.cellWidth));
}
function lastRow() {
var columns = Math.floor(width / itemGrid.cellWidth);
return Math.ceil(count / columns) - 1;
}
function tryActivate(row, col) {
if (count) {
var columns = Math.floor(width / itemGrid.cellWidth);
var rows = Math.ceil(count / columns);
row = Math.min(row, rows - 1);
col = Math.min(col, columns - 1);
currentIndex = Math.min(row ? ((Math.max(1, row) * columns) + col)
: col,
count - 1);
focus = true;
}
}
function forceLayout() {
gridView.forceLayout();
}
ActionMenu {
id: actionMenu
onActionClicked: {
visualParent.actionTriggered(actionId, actionArgument);
}
}
DropArea {
id: dropArea
width: itemGrid.width
height: itemGrid.height
onPositionChanged: event => {
if (!itemGrid.dropEnabled || gridView.animating || !kicker.dragSource) {
return;
}
var x = Math.max(0, event.x - (width % itemGrid.cellWidth));
var cPos = mapToItem(gridView.contentItem, x, event.y);
var item = gridView.itemAt(cPos.x, cPos.y);
if (item) {
if (kicker.dragSource.parent === gridView.contentItem) {
if (item !== kicker.dragSource) {
item.GridView.view.model.moveRow(dragSource.itemIndex, item.itemIndex);
}
} else if (kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model
&& !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) {
var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1);
itemGrid.model.dropPlaceholderIndex = item.itemIndex;
if (!hasPlaceholder) {
gridView.currentIndex = (item.itemIndex - 1);
}
}
} else if (kicker.dragSource.parent !== gridView.contentItem
&& kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model
&& !itemGrid.model.isFavorite(kicker.dragSource.favoriteId)) {
var hasPlaceholder = (itemGrid.model.dropPlaceholderIndex !== -1);
itemGrid.model.dropPlaceholderIndex = hasPlaceholder ? itemGrid.model.count - 1 : itemGrid.model.count;
if (!hasPlaceholder) {
gridView.currentIndex = (itemGrid.model.count - 1);
}
} else {
itemGrid.model.dropPlaceholderIndex = -1;
gridView.currentIndex = -1;
}
}
onExited: {
if ("dropPlaceholderIndex" in itemGrid.model) {
itemGrid.model.dropPlaceholderIndex = -1;
gridView.currentIndex = -1;
}
}
onDropped: {
if (kicker.dragSource && kicker.dragSource.parent !== gridView.contentItem && kicker.dragSource.GridView.view.model.favoritesModel === itemGrid.model) {
itemGrid.model.addFavorite(kicker.dragSource.favoriteId, itemGrid.model.dropPlaceholderIndex);
gridView.currentIndex = -1;
}
}
Timer {
id: resetAnimationDurationTimer
interval: 120
repeat: false
onTriggered: {
gridView.animationDuration = interval - 20;
}
}
GridView {
id: gridView
width: itemGrid.width
height: itemGrid.height
signal itemContainsMouseChanged(bool containsMouse)
property int iconSize: Kirigami.Units.iconSizes.huge
property bool animating: false
property int animationDuration: itemGrid.dropEnabled ? resetAnimationDurationTimer.interval : 0
focus: true
currentIndex: -1
ScrollBar.vertical: ScrollBar {
snapMode: ScrollBar.SnapAlways
}
snapMode: GridView.SnapOneRow
move: Transition {
enabled: itemGrid.dropEnabled
SequentialAnimation {
PropertyAction { target: gridView; property: "animating"; value: true }
NumberAnimation {
duration: gridView.animationDuration
properties: "x, y"
easing.type: Easing.OutQuad
}
PropertyAction { target: gridView; property: "animating"; value: false }
}
}
moveDisplaced: Transition {
enabled: itemGrid.dropEnabled
SequentialAnimation {
PropertyAction { target: gridView; property: "animating"; value: true }
NumberAnimation {
duration: gridView.animationDuration
properties: "x, y"
easing.type: Easing.OutQuad
}
PropertyAction { target: gridView; property: "animating"; value: false }
}
}
keyNavigationWraps: false
boundsBehavior: Flickable.StopAtBounds
delegate: ItemGridDelegate {
showLabel: itemGrid.showLabels
}
highlight: Rectangle { color: colorWithAlpha(Kirigami.Theme.highlightColor,0.65); radius: 10 }
/*
highlight: Item {
property bool isDropPlaceHolder: "dropPlaceholderIndex" in itemGrid.model && itemGrid.currentIndex === itemGrid.model.dropPlaceholderIndex
PlasmaExtras.Highlight {
visible: gridView.currentItem && !isDropPlaceHolder
hovered: true
pressed: hoverArea.pressed
anchors.fill: parent
}
KSvg.FrameSvgItem {
visible: gridView.currentItem && isDropPlaceHolder
anchors.fill: parent
imagePath: "widgets/viewitem"
prefix: "selected"
opacity: 0.5
Kirigami.Icon {
anchors {
right: parent.right
rightMargin: parent.margins.right
bottom: parent.bottom
bottomMargin: parent.margins.bottom
}
width: Kirigami.Units.iconSizes.smallMedium
height: width
source: "list-add"
active: false
}
}
}
*/
highlightFollowsCurrentItem: true
highlightMoveDuration: 0
onCurrentIndexChanged: {
if (currentIndex !== -1) {
hoverArea.hoverEnabled = false
focus = true;
}
}
onCountChanged: {
animationDuration = 0;
resetAnimationDurationTimer.start();
if (count > 0 && itemGrid.grabFocus) {
currentIndex = 0;
focus = true;
forceActiveFocus()
}
}
onModelChanged: {
currentIndex = -1;
}
Keys.onLeftPressed: event => {
if (itemGrid.currentCol() !== 0) {
event.accepted = true;
moveCurrentIndexLeft();
} else {
itemGrid.keyNavLeft();
}
}
Keys.onRightPressed: event => {
var columns = Math.floor(width / cellWidth);
if (itemGrid.currentCol() !== columns - 1 && currentIndex !== count -1) {
event.accepted = true;
moveCurrentIndexRight();
} else {
itemGrid.keyNavRight();
}
}
Keys.onUpPressed: event => {
if (itemGrid.currentRow() !== 0) {
event.accepted = true;
moveCurrentIndexUp();
positionViewAtIndex(currentIndex, GridView.Contain);
} else {
itemGrid.keyNavUp();
}
}
Keys.onDownPressed: event => {
if (itemGrid.currentRow() < itemGrid.lastRow()) {
// Fix moveCurrentIndexDown()'s lack of proper spatial nav down
// into partial columns.
event.accepted = true;
var columns = Math.floor(itemGrid.width / cellWidth);
var newIndex = currentIndex + columns;
currentIndex = Math.min(newIndex, gridView.count - 1);
positionViewAtIndex(currentIndex, GridView.Visible);
} else {
itemGrid.keyNavDown();
}
}
onItemContainsMouseChanged: containsMouse => {
if (!containsMouse) {
//if (!actionMenu.opened) {
// gridView.currentIndex = -1;
//}
hoverArea.pressX = -1;
hoverArea.pressY = -1;
hoverArea.lastX = -1;
hoverArea.lastY = -1;
hoverArea.pressedItem = null;
hoverArea.hoverEnabled = true;
}
}
}
//<>}
MouseArea {
id: hoverArea
width: itemGrid.width - Kirigami.Units.gridUnit
height: itemGrid.height
//anchors.fill: parent
property int pressX: -1
property int pressY: -1
property int lastX: -1
property int lastY: -1
property Item pressedItem: null
acceptedButtons: Qt.LeftButton | Qt.RightButton
hoverEnabled: true
function updatePositionProperties(x, y) {
// Prevent hover event synthesis in QQuickWindow interfering
// with keyboard navigation by ignoring repeated events with
// identical coordinates. As the work done here would be re-
// dundant in any case, these are safe to ignore.
if (lastX === x && lastY === y) {
return;
}
lastX = x;
lastY = y;
var cPos = mapToItem(gridView.contentItem, x, y);
var item = gridView.itemAt(cPos.x, cPos.y);
if (!item) {
gridView.currentIndex = -1;
pressedItem = null;
} else {
itemGrid.focus = (item.itemIndex !== -1)
itemGrid.forceActiveFocus() //<>
gridView.currentIndex = item.itemIndex;
}
return item;
}
onPressed: mouse => {
mouse.accepted = true;
updatePositionProperties(mouse.x, mouse.y);
pressX = mouse.x;
pressY = mouse.y;
if (mouse.button === Qt.RightButton) {
if (gridView.currentItem) {
if (gridView.currentItem.hasActionList) {
var mapped = mapToItem(gridView.currentItem, mouse.x, mouse.y);
gridView.currentItem.openActionMenu(mapped.x, mapped.y);
}
} else {
var mapped = mapToItem(rootItem, mouse.x, mouse.y);
contextMenu.open(mapped.x, mapped.y);
}
} else {
pressedItem = gridView.currentItem;
}
}
onReleased: mouse => {
mouse.accepted = true;
updatePositionProperties(mouse.x, mouse.y);
if (!dragHelper.dragging) {
if (pressedItem) {
if ("trigger" in gridView.model) {
gridView.model.trigger(pressedItem.itemIndex, "", null);
root.toggle();
}
itemGrid.itemActivated(pressedItem.itemIndex, "", null);
} else if (mouse.button === Qt.LeftButton) {
root.toggle();
}
}
pressX = pressY = -1;
pressedItem = null;
}
onPositionChanged: mouse => {
var item = pressedItem? pressedItem : updatePositionProperties(mouse.x, mouse.y);
if (gridView.currentIndex !== -1) {
if (itemGrid.dragEnabled && pressX !== -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) {
if ("pluginName" in item.m) {
dragHelper.startDrag(kicker, item.url, item.icon,
"text/x-plasmoidservicename", item.m.pluginName);
} else {
//dragHelper.startDrag(kicker, item.url, item.icon);
dragHelper.startDrag(kicker, item.url);
}
kicker.dragSource = item;
pressX = -1;
pressY = -1;
}
}
}
}
}
}
@@ -0,0 +1,137 @@
/*
SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami 2.20 as Kirigami
import "code/tools.js" as Tools
Item {
id: item
width: ListView.view.width
height: 40
enabled: !model.disabled
property bool showLabel: true
property int itemIndex: model.index
property string favoriteId: model.favoriteId !== undefined ? model.favoriteId : ""
property url url: model.url !== undefined ? model.url : ""
property variant icon: model.decoration !== undefined ? model.decoration : ""
property var m: model
property bool hasActionList: ((model.favoriteId !== null)
|| (("hasActionList" in model) && (model.hasActionList === true)))
Accessible.role: Accessible.MenuItem
Accessible.name: model.display
function openActionMenu(x, y) {
var actionList = hasActionList ? model.actionList : [];
Tools.fillActionMenu(i18n, actionMenu, actionList, GridView.view.model.favoritesModel, model.favoriteId);
actionMenu.visualParent = item;
actionMenu.open(x, y);
}
function actionTriggered(actionId, actionArgument) {
var close = (Tools.triggerAction(GridView.view.model, model.index, actionId, actionArgument) === true);
if (close) {
root.toggle();
}
}
Kirigami.Icon {
id: icon
//y: item.showLabel ? (2 * highlightItemSvg.margins.top) : undefined
anchors.left: parent.left
anchors.leftMargin: Kirigami.Units.largeSpacing
anchors.verticalCenter: parent.verticalCenter
width: iconSize
height: width
animated: false
source: model.decoration
}
PlasmaComponents3.Label {
id: label
visible: item.showLabel
anchors {
left: icon.right
leftMargin: Kirigami.Units.largeSpacing
right: desc.left
rightMargin: Kirigami.Units.largeSpacing
verticalCenter: icon.verticalCenter
}
horizontalAlignment: Text.AlignLeft
maximumLineCount: 1
elide: Text.ElideMiddle
//wrapMode: Text.Wrap
color: Kirigami.Theme.textColor
font.pointSize: Kirigami.Theme.defaultFont.pointSize
text: ("name" in model ? model.name : model.display)
textFormat: Text.PlainText
}
PlasmaComponents3.Label {
id: desc
anchors {
//top: itemColumns == 2 ? label.bottom: undefined
//left: itemColumns == 2 ? icon.right : undefined
leftMargin: Kirigami.Units.largeSpacing
right: parent.right
rightMargin: Kirigami.Units.largeSpacing
verticalCenter: icon.verticalCenter
}
horizontalAlignment: Text.AlignRight
maximumLineCount: 1
elide: Text.ElideMiddle
//wrapMode: Text.Wrap
color: colorWithAlpha(Kirigami.Theme.textColor,0.4)
font.pointSize: Kirigami.Theme.defaultFont.pointSize - 1
text: ("description" in model ? model.description : "")
textFormat: Text.PlainText
}
PlasmaCore.ToolTipArea {
id: toolTip
property string text: model.display
anchors.fill: parent
active: root.visible && label.truncated
mainItem: toolTipDelegate
//<>onContainsMouseChanged: item.GridView.view.itemContainsMouseChanged(containsMouse)
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Menu && hasActionList) {
event.accepted = true;
openActionMenu(item);
} else if ((event.key === Qt.Key_Enter || event.key === Qt.Key_Return)) {
event.accepted = true;
if ("trigger" in GridView.view.model) {
GridView.view.model.trigger(index, "", null);
root.toggle();
}
itemGrid.itemActivated(index, "", null);
}
}
}
@@ -0,0 +1,99 @@
/*
SPDX-FileCopyrightText: 2013-2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.private.kicker 0.1 as Kicker
Kicker.SubMenu {
id: itemDialog
property alias focusParent: itemListView.focusParent
property alias model: funnelModel.sourceModel
property bool aboutToBeDestroyed: false
visible: false
hideOnWindowDeactivate: kicker.hideOnWindowDeactivate
location: PlasmaCore.Types.Floating
offset: Kirigami.Units.smallSpacing
onWindowDeactivated: {
if (!aboutToBeDestroyed) {
kicker.expanded = false;
}
}
mainItem: ItemListView {
id: itemListView
height: {
const m = funnelModel.sourceModel;
if (m === null || m === undefined) {
// TODO: setting height to 0 triggers a warning in PlasmaQuick::Dialog
return 0;
}
return Math.min(
// either fit in screen boundaries (cut to the nearest item/separator boundary), ...
__subFloorMultipleOf(
itemDialog.availableScreenRectForItem(itemListView).height
- itemDialog.margins.top
- itemDialog.margins.bottom,
itemHeight
) + m.separatorCount * (separatorHeight - itemHeight)
,
// ...or fit the content itself -- whichever is shorter.
((m.count - m.separatorCount) * itemHeight)
+ (m.separatorCount * separatorHeight)
);
}
// get x rounded down to the multiple of y, minus extra y.
function __subFloorMultipleOf(x : real, y : real) : real {
return (Math.floor(x / y) - 1) * y;
}
iconsEnabled: true
dialog: itemDialog
model: funnelModel
Kicker.FunnelModel {
id: funnelModel
property bool sorted: sourceModel?.sorted ?? false
Component.onCompleted: {
kicker.reset.connect(funnelModel.reset);
}
onCountChanged: {
if (sourceModel && count === 0) {
itemDialog.delayedDestroy();
}
}
onSourceModelChanged: {
itemListView.currentIndex = -1;
}
}
}
function delayedDestroy() {
aboutToBeDestroyed = true;
Plasmoid.hideOnWindowDeactivate = false;
visible = false;
Qt.callLater(() => itemDialog.destroy());
}
}
@@ -0,0 +1,267 @@
/*
SPDX-FileCopyrightText: 2013-2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Controls
import org.kde.kquickcontrolsaddons 2.0
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
FocusScope {
id: itemList
property real minimumWidth: Kirigami.Units.gridUnit * 14
property real maximumWidth: minimumWidth * 2
width: minimumWidth
height: listView.contentHeight
signal exited
signal keyNavigationAtListEnd
signal appendSearchText(string text)
property Item focusParent: null
property QtObject dialog: null
property QtObject childDialog: null
property bool iconsEnabled: false
property int itemHeight: Math.ceil((Math.max(Kirigami.Units.iconSizes.sizeForLabels, Kirigami.Units.iconSizes.small)
+ Math.max(highlightItemSvg.margins.top + highlightItemSvg.margins.bottom,
listItemSvg.margins.top + listItemSvg.margins.bottom)) / 2) * 2
property int separatorHeight: model.sorted === true ? 0 : lineSvg.horLineHeight + (2 * Kirigami.Units.smallSpacing)
property alias currentIndex: listView.currentIndex
property alias currentItem: listView.currentItem
property alias keyNavigationWraps: listView.keyNavigationWraps
property alias showChildDialogs: listView.showChildDialogs
property alias model: listView.model
property alias count: listView.count
property alias containsMouse: listener.containsMouse
property alias resetOnExitDelay: resetIndexTimer.interval
onFocusParentChanged: {
appendSearchText.connect(focusParent.appendSearchText);
}
Timer {
id: dialogSpawnTimer
property bool focusOnSpawn: false
interval: 70
repeat: false
onTriggered: {
if (!kicker.expanded || model === undefined || currentIndex == -1) {
return;
}
if (itemList.childDialog != null) {
itemList.childDialog.delayedDestroy();
}
// Gets reenabled after the dialog spawn causes a focus-in on the dialog window.
kicker.hideOnWindowDeactivate = false;
itemList.childDialog = itemListDialogComponent.createObject(itemList);
itemList.childDialog.focusParent = itemList;
itemList.childDialog.visualParent = listView.currentItem;
itemList.childDialog.model = model.modelForRow(listView.currentIndex);
itemList.childDialog.visible = true;
windowSystem.forceActive(itemList.childDialog.mainItem);
itemList.childDialog.mainItem.focus = true;
if (focusOnSpawn) {
itemList.childDialog.mainItem.showChildDialogs = false;
itemList.childDialog.mainItem.currentIndex = 0;
itemList.childDialog.mainItem.showChildDialogs = true;
}
}
}
Timer {
id: resetIndexTimer
interval: (dialog != null) ? 50 : 150
repeat: false
onTriggered: {
if (focus && (!itemList.childDialog || !itemList.childDialog.mainItem.containsMouse)) {
currentIndex = -1;
itemList.exited();
}
}
}
MouseEventListener {
id: listener
anchors.fill: parent
hoverEnabled: true
onContainsMouseChanged: {
listView.eligibleWidth = listView.width;
if (containsMouse) {
resetIndexTimer.stop();
itemList.forceActiveFocus();
} else if ((!itemList.childDialog || !dialog)
&& (!currentItem || !currentItem.menu.opened)) {
resetIndexTimer.start();
}
}
ScrollView {
anchors.fill: parent
focus: true
ListView {
id: listView
property bool showChildDialogs: true
property int eligibleWidth: width
currentIndex: -1
boundsBehavior: Flickable.StopAtBounds
snapMode: ListView.SnapToItem
spacing: 0
keyNavigationEnabled: false
delegate: ItemListDelegate {
onFullTextWidthChanged: {
if (fullTextWidth > itemList.width) itemList.width = Math.min(fullTextWidth, itemList.maximumWidth);
}
}
highlight: PlasmaExtras.Highlight {
visible: !listView.currentItem || !listView.currentItem.isSeparator
pressed: listView.currentItem && listView.currentItem.pressed && !listView.currentItem.hasChildren
active: listView.currentItem && listView.currentItem.hovered
}
highlightMoveDuration: 0
onCountChanged: {
if (currentIndex == 0) {
currentItem.forceActiveFocus();
} else {
currentIndex = -1;
}
}
onCurrentIndexChanged: {
if (currentIndex != -1) {
if (itemList.childDialog) {
if (currentItem && currentItem.hasChildren) {
itemList.childDialog.mainItem.width = itemList.minimumWidth;
itemList.childDialog.model = model.modelForRow(currentIndex);
itemList.childDialog.visualParent = listView.currentItem;
} else {
itemList.childDialog.delayedDestroy();
}
return;
}
if (currentItem == null || !currentItem.hasChildren || !kicker.expanded) {
dialogSpawnTimer.stop();
return;
}
if (showChildDialogs) {
dialogSpawnTimer.focusOnSpawn = false;
dialogSpawnTimer.restart();
}
} else if (itemList.childDialog != null) {
itemList.childDialog.delayedDestroy();
itemList.childDialog = null;
}
}
onCurrentItemChanged: {
if (currentItem) {
currentItem.menu.closed.connect(resetIndexTimer.restart);
}
}
}
Keys.onPressed: event => {
if (event.key === Qt.Key_Right || event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
if (itemList.childDialog === null && currentItem != null && currentItem.hasChildren) {
dialogSpawnTimer.focusOnSpawn = true;
dialogSpawnTimer.restart();
} else if (currentItem != null && currentItem.hasChildren) {
windowSystem.forceActive(itemList.childDialog.mainItem);
itemList.childDialog.mainItem.focus = true;
itemList.childDialog.mainItem.currentIndex = 0;
}
} else if (event.key === Qt.Key_Up) {
event.accepted = true;
if (!keyNavigationWraps && currentIndex == 0) {
itemList.keyNavigationAtListEnd();
return;
}
showChildDialogs = false;
listView.decrementCurrentIndex();
if (currentItem.isSeparator) {
listView.decrementCurrentIndex();
}
listView.currentItem.forceActiveFocus()
showChildDialogs = true;
} else if (event.key === Qt.Key_Down) {
event.accepted = true;
if (!keyNavigationWraps && currentIndex == count - 1) {
itemList.keyNavigationAtListEnd();
return;
}
showChildDialogs = false;
listView.incrementCurrentIndex();
if (currentItem.isSeparator) {
listView.incrementCurrentIndex();
}
listView.currentItem.forceActiveFocus()
showChildDialogs = true;
} else if (event.key === Qt.Key_Left && dialog != null) {
dialog.destroy();
} else if (event.key === Qt.Key_Escape) {
kicker.expanded = false;
} else if (event.key === Qt.Key_Tab) {
//do nothing, and skip appending text
} else if (event.text !== "") {
if (/[\x00-\x1F\x7F]/.test(event.text)) {
// We still want to focus it
appendSearchText("");
} else {
appendSearchText(event.text);
}
}
}
}
}
Component.onCompleted: {
windowSystem.monitorWindowFocus(itemList);
if (dialog == null) {
appendSearchText.connect(root.appendSearchText);
}
}
}
@@ -0,0 +1,235 @@
/*
SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.components as PlasmaComponents
import org.kde.plasma.extras 2.0 as PlasmaExtras
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.private.kicker 0.1 as Kicker
PlasmaComponents.ScrollView {
id: itemMultiGrid
anchors {
top: parent.top
}
width: parent.width
implicitHeight: itemColumn.implicitHeight
signal keyNavLeft(int subGridIndex)
signal keyNavRight(int subGridIndex)
signal keyNavUp()
signal keyNavDown()
property bool grabFocus: false
property alias model: repeater.model
property alias count: repeater.count
property alias flickableItem: flickable
function subGridAt(index) {
return repeater.itemAt(index).itemGrid;
}
function tryActivate(row, col) { // FIXME TODO: Cleanup messy algo.
if (flickable.contentY > 0) {
row = 0;
}
var target = null;
var rows = 0;
for (var i = 0; i < repeater.count; i++) {
var grid = subGridAt(i);
if (rows <= row) {
target = grid;
rows += grid.lastRow() + 2; // Header counts as one.
} else {
break;
}
}
if (target) {
rows -= (target.lastRow() + 2);
target.tryActivate(row - rows, col);
}
}
onFocusChanged: {
if (!focus) {
for (var i = 0; i < repeater.count; i++) {
subGridAt(i).focus = false;
}
}
}
Flickable {
id: flickable
flickableDirection: Flickable.VerticalFlick
contentHeight: itemColumn.implicitHeight
//focusPolicy: Qt.NoFocus
Column {
id: itemColumn
width: itemMultiGrid.width - Kirigami.Units.gridUnit
Repeater {
id: repeater
delegate: Item {
width: itemColumn.width - Kirigami.Units.gridUnit
height: headerHeight + gridView.height + (index == repeater.count - 1 ? 0 : footerHeight)
property int headerHeight: (gridViewLabel.height
+ gridViewLabelUnderline.height + Kirigami.Units.gridUnit)
property int footerHeight: (Math.ceil(headerHeight / cellSize) * cellSize) - headerHeight
property Item itemGrid: gridView
Kirigami.Heading {
id: gridViewLabel
anchors.top: parent.top
x: Kirigami.Units.smallSpacing
width: parent.width - x
height: dummyHeading.height
elide: Text.ElideRight
wrapMode: Text.NoWrap
opacity: 1.0
color: "white" // FIXME TODO: Respect theming?
level: 1
text: repeater.model.modelForRow(index).description
textFormat: Text.PlainText
}
KSvg.SvgItem {
id: gridViewLabelUnderline
anchors.top: gridViewLabel.bottom
width: parent.width - Kirigami.Units.gridUnit
height: lineSvg.horLineHeight
svg: lineSvg
elementId: "horizontal-line"
}
MouseArea {
width: parent.width
height: parent.height
onClicked: root.toggle()
}
ItemGridView {
id: gridView
anchors {
top: gridViewLabelUnderline.bottom
topMargin: Kirigami.Units.gridUnit
}
width: parent.width
height: Math.ceil(count / Math.floor(width / cellSize)) * cellSize
cellWidth: cellSize
cellHeight: cellSize
iconSize: root.iconSize
verticalScrollBarPolicy: PlasmaComponents.ScrollBar.AlwaysOff
model: repeater.model.modelForRow(index)
onFocusChanged: {
if (focus) {
itemMultiGrid.focus = true;
}
}
onCountChanged: {
if (itemMultiGrid.grabFocus && index == 0 && count > 0) {
currentIndex = 0;
focus = true;
}
}
onCurrentItemChanged: {
if (!currentItem) {
return;
}
if (index == 0 && currentRow() === 0) {
flickable.contentY = 0;
return;
}
var y = currentItem.y;
y = contentItem.mapToItem(flickable.contentItem, 0, y).y;
if (y < flickable.contentY) {
flickable.contentY = y;
} else {
y += cellSize;
y -= flickable.contentY;
y -= itemMultiGrid.height;
if (y > 0) {
flickable.contentY += y;
}
}
}
onKeyNavLeft: {
itemMultiGrid.keyNavLeft(index);
}
onKeyNavRight: {
itemMultiGrid.keyNavRight(index);
}
onKeyNavUp: {
if (index > 0) {
var prevGrid = subGridAt(index - 1);
prevGrid.tryActivate(prevGrid.lastRow(), currentCol());
} else {
itemMultiGrid.keyNavUp();
}
}
onKeyNavDown: {
if (index < repeater.count - 1) {
subGridAt(index + 1).tryActivate(0, currentCol());
} else {
itemMultiGrid.keyNavDown();
}
}
}
// HACK: Steal wheel events from the nested grid view and forward them to
// the ScrollView's internal WheelArea.
Kicker.WheelInterceptor {
anchors.fill: gridView
z: 1
destination: findWheelArea(itemMultiGrid)
}
}
}
}
}
}
@@ -0,0 +1,142 @@
/*
SPDX-FileCopyrightText: 2013-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.kquickcontrolsaddons 2.0
import org.kde.plasma.core as PlasmaCore
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.plasmoid 2.0
import "code/tools.js" as Tools
Item {
id: item
width: root.width
height: root.width
signal actionTriggered(string actionId, variant actionArgument)
signal aboutToShowActionMenu(variant actionMenu)
property bool hasActionList: ((model.favoriteId !== null)
|| (("hasActionList" in model) && (model.hasActionList !== null)))
property int itemIndex: model.index
onAboutToShowActionMenu: actionMenu => {
const actionList = (model.hasActionList !== null) ? model.actionList : [];
Tools.fillActionMenu(i18n, actionMenu, actionList, repeater.model, model.favoriteId);
}
onActionTriggered: (actionId, actionArgument) => {
if (Tools.triggerAction(repeater.model, model.index, actionId, actionArgument) === true) {
kicker.expanded = false;
}
}
function openActionMenu(visualParent, x, y) {
aboutToShowActionMenu(actionMenu);
actionMenu.visualParent = visualParent;
actionMenu.open(x, y);
}
ActionMenu {
id: actionMenu
onActionClicked: {
actionTriggered(actionId, actionArgument);
}
}
Kirigami.Icon {
anchors.fill: parent
active: toolTip.containsMouse
source: model.decoration
}
MouseEventListener {
id: listener
anchors {
fill: parent
leftMargin: - sideBar.margins.left
rightMargin: - sideBar.margins.right
}
enabled: (item.parent && !item.parent.animating)
property bool pressed: false
property int pressX: -1
property int pressY: -1
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
onPressed: {
if (mouse.buttons & Qt.RightButton) {
if (item.hasActionList) {
item.openActionMenu(item, mouse.x, mouse.y);
}
} else {
pressed = true;
pressX = mouse.x;
pressY = mouse.y;
}
}
onReleased: {
if (pressed) {
repeater.model.trigger(index, "", null);
kicker.expanded = false;
}
pressed = false;
pressX = -1;
pressY = -1;
}
onContainsMouseChanged: {
if (!containsMouse) {
pressed = false;
pressX = -1;
pressY = -1;
}
}
onPositionChanged: {
if (pressX !== -1 && dragHelper.isDrag(pressX, pressY, mouse.x, mouse.y)) {
kicker.dragSource = item;
dragHelper.startDrag(kicker, model.url, model.icon);
pressed = false;
pressX = -1;
pressY = -1;
return;
}
}
}
PlasmaCore.ToolTipArea {
id: toolTip
property string text: model.display
anchors {
fill: parent
leftMargin: - sideBar.margins.left
rightMargin: - sideBar.margins.right
}
interactive: false
location: (((Plasmoid.location === PlasmaCore.Types.RightEdge)
|| (Qt.application.layoutDirection === Qt.RightToLeft))
? PlasmaCore.Types.RightEdge : PlasmaCore.Types.LeftEdge)
mainItem: toolTipDelegate
}
}
@@ -0,0 +1,83 @@
/*
SPDX-FileCopyrightText: 2013-2014 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import org.kde.draganddrop 2.0
import org.kde.kirigami 2.20 as Kirigami
DropArea {
id: root
width: Kirigami.Units.iconSizes.medium
height: contentHeight
anchors.horizontalCenter: parent.horizontalCenter
property int contentHeight: model ? (model.count * Kirigami.Units.iconSizes.medium) + ((model.count - 1) * flow.spacing) : 0
property alias model: repeater.model
onDragMove: event => {
if (flow.animating) {
return;
}
var above = flow.childAt(event.x, event.y);
if (above && above !== kicker.dragSource && dragSource.parent == flow) {
repeater.model.moveRow(dragSource.itemIndex, above.itemIndex);
}
}
Flow {
id: flow
anchors.fill: parent
property bool animating: false
property int animationDuration: resetAnimationDurationTimer.interval
move: Transition {
SequentialAnimation {
PropertyAction { target: flow; property: "animating"; value: true }
NumberAnimation {
duration: flow.animationDuration
properties: "x, y"
easing.type: Easing.OutQuad
}
PropertyAction { target: flow; property: "animating"; value: false }
}
}
spacing: (2 * Kirigami.Units.smallSpacing)
Repeater {
id: repeater
delegate: SideBarItem {}
onCountChanged: {
flow.animationDuration = 0;
resetAnimationDurationTimer.start();
}
}
}
Timer {
id: resetAnimationDurationTimer
interval: 150
repeat: false
onTriggered: {
flow.animationDuration = interval - 20;
}
}
}
@@ -0,0 +1,181 @@
/*
SPDX-FileCopyrightText: 2013 Aurélien Gâteau <agateau@kde.org>
SPDX-FileCopyrightText: 2013-2015 Eike Hein <hein@kde.org>
SPDX-FileCopyrightText: 2017 Ivan Cukic <ivan.cukic@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
.pragma library
function fillActionMenu(i18n, actionMenu, actionList, favoriteModel, favoriteId) {
// Accessing actionList can be a costly operation, so we don't
// access it until we need the menu.
var actions = createFavoriteActions(i18n, favoriteModel, favoriteId);
if (actions) {
if (actionList && actionList.length > 0) {
var actionListCopy = Array.from(actionList);
var separator = { "type": "separator" };
actionListCopy.push(separator);
// actionList = actions.concat(actionList); // this crashes Qt O.o
actionListCopy.push.apply(actionListCopy, actions);
actionList = actionListCopy;
} else {
actionList = actions;
}
}
actionMenu.actionList = actionList;
}
function createFavoriteActions(i18n, favoriteModel, favoriteId) {
if (!favoriteModel || !favoriteModel.enabled || !favoriteId) {
return null;
}
if (favoriteModel.activities === undefined ||
favoriteModel.activities.runningActivities.length <= 1) {
var action = {};
if (favoriteModel.isFavorite(favoriteId)) {
action.text = i18n("Remove from Favorites");
action.icon = "bookmark-remove";
action.actionId = "_kicker_favorite_remove";
} else if (favoriteModel.maxFavorites === -1 || favoriteModel.count < favoriteModel.maxFavorites) {
action.text = i18n("Add to Favorites");
action.icon = "bookmark-new";
action.actionId = "_kicker_favorite_add";
} else {
return null;
}
action.actionArgument = { favoriteModel: favoriteModel, favoriteId: favoriteId };
return [action];
} else {
var actions = [];
var linkedActivities = favoriteModel.linkedActivitiesFor(favoriteId);
var activities = favoriteModel.activities.runningActivities;
// Adding the item to link/unlink to all activities
var linkedToAllActivities =
!(linkedActivities.indexOf(":global") === -1);
actions.push({
text : i18n("On All Activities"),
checkable : true,
actionId : linkedToAllActivities ?
"_kicker_favorite_remove_from_activity" :
"_kicker_favorite_set_to_activity",
checked : linkedToAllActivities,
actionArgument : {
favoriteModel: favoriteModel,
favoriteId: favoriteId,
favoriteActivity: ""
}
});
// Adding items for each activity separately
var addActivityItem = function(activityId, activityName) {
var linkedToThisActivity =
!(linkedActivities.indexOf(activityId) === -1);
actions.push({
text : activityName,
checkable : true,
checked : linkedToThisActivity && !linkedToAllActivities,
actionId :
// If we are on all activities, and the user clicks just one
// specific activity, unlink from everything else
linkedToAllActivities ? "_kicker_favorite_set_to_activity" :
// If we are linked to the current activity, just unlink from
// that single one
linkedToThisActivity ? "_kicker_favorite_remove_from_activity" :
// Otherwise, link to this activity, but do not unlink from
// other ones
"_kicker_favorite_add_to_activity",
actionArgument : {
favoriteModel : favoriteModel,
favoriteId : favoriteId,
favoriteActivity : activityId
}
});
};
// Adding the item to link/unlink to the current activity
addActivityItem(favoriteModel.activities.currentActivity, i18n("On the Current Activity"));
actions.push({
type: "separator",
actionId: "_kicker_favorite_separator"
});
// Adding the items for each activity
activities.forEach(function(activityId) {
addActivityItem(activityId, favoriteModel.activityNameForId(activityId));
});
return [{
text : i18n("Show in Favorites"),
icon : "favorite",
subActions : actions
}];
}
}
function triggerAction(model, index, actionId, actionArgument) {
function startsWith(txt, needle) {
return txt.substr(0, needle.length) === needle;
}
if (startsWith(actionId, "_kicker_favorite_")) {
handleFavoriteAction(actionId, actionArgument);
return;
}
var closeRequested = model.trigger(index, actionId, actionArgument);
if (closeRequested) {
return true;
}
return false;
}
function handleFavoriteAction(actionId, actionArgument) {
var favoriteId = actionArgument.favoriteId;
var favoriteModel = actionArgument.favoriteModel;
if (favoriteModel === null || favoriteId === null) {
return null;
}
if (actionId === "_kicker_favorite_remove") {
favoriteModel.removeFavorite(favoriteId);
} else if (actionId === "_kicker_favorite_add") {
favoriteModel.addFavorite(favoriteId);
} else if (actionId === "_kicker_favorite_remove_from_activity") {
favoriteModel.removeFavoriteFrom(favoriteId, actionArgument.favoriteActivity);
} else if (actionId === "_kicker_favorite_add_to_activity") {
favoriteModel.addFavoriteTo(favoriteId, actionArgument.favoriteActivity);
} else if (actionId === "_kicker_favorite_set_to_activity") {
favoriteModel.setFavoriteOn(favoriteId, actionArgument.favoriteActivity);
}
}
@@ -0,0 +1,274 @@
/*
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQuick.Layouts 1.15
import org.kde.plasma.components 3.0 as PlasmaComponents3
import org.kde.plasma.core as PlasmaCore
import org.kde.ksvg 1.0 as KSvg
import org.kde.plasma.plasmoid 2.0
import org.kde.kirigami 2.20 as Kirigami
import org.kde.plasma.private.kicker 0.1 as Kicker
import org.kde.plasma.plasma5support 2.0 as P5Support
PlasmoidItem {
id: kicker
anchors.fill: parent
signal reset
property bool isDash: true // Plasmoid.pluginName === "org.kde.plasma.kickerdash"
switchWidth: isDash || !fullRepresentationItem ? 0 :fullRepresentationItem.Layout.minimumWidth
switchHeight: isDash || !fullRepresentationItem ? 0 :fullRepresentationItem.Layout.minimumHeight
// this is a bit of a hack to prevent Plasma from spawning a dialog on its own when we're Dash
preferredRepresentation: isDash ?fullRepresentation : null
compactRepresentation: isDash ? null : compactRepresentation
fullRepresentation: compactRepresentation
property Component itemListDialogComponent: Qt.createComponent(Qt.resolvedUrl("./ItemListDialog.qml"))
property Item dragSource: null
property QtObject globalFavorites: rootModel.favoritesModel
property QtObject systemFavorites: rootModel.systemFavoritesModel
Plasmoid.icon: Plasmoid.configuration.useCustomButtonImage ? Plasmoid.configuration.customButtonImage : Plasmoid.configuration.icon
onSystemFavoritesChanged: {
systemFavorites.favorites = Plasmoid.configuration.favoriteSystemActions;
}
function action_menuedit() {
processRunner.runMenuEditor();
}
function updateSvgMetrics() {
lineSvg.horLineHeight = lineSvg.elementSize("horizontal-line").height;
lineSvg.vertLineWidth = lineSvg.elementSize("vertical-line").width;
}
Component {
id: compactRepresentation
CompactRepresentation {}
}
Kicker.RootModel {
id: rootModel
autoPopulate: false
appNameFormat: Plasmoid.configuration.appNameFormat
flat: kicker.isDash || Plasmoid.configuration.limitDepth
sorted: Plasmoid.configuration.alphaSort
showSeparators: !kicker.isDash
// TODO: appletInterface property now can be ported to "applet" and have the real Applet* assigned directly
appletInterface: kicker
showAllApps: kicker.isDash
showAllAppsCategorized: false //<> true
showTopLevelItems: !kicker.isDash
showRecentApps: true //<>Plasmoid.configuration.showRecentApps
showRecentDocs: true //<>Plasmoid.configuration.showRecentDocs
recentOrdering: Plasmoid.configuration.recentOrdering
onShowRecentAppsChanged: {
Plasmoid.configuration.showRecentApps = showRecentApps;
}
onShowRecentDocsChanged: {
Plasmoid.configuration.showRecentDocs = showRecentDocs;
}
onRecentOrderingChanged: {
Plasmoid.configuration.recentOrdering = recentOrdering;
}
Component.onCompleted: {
favoritesModel.initForClient("org.kde.plasma.kicker.favorites.instance-" + Plasmoid.id)
if (!Plasmoid.configuration.favoritesPortedToKAstats) {
if (favoritesModel.count < 1) {
favoritesModel.portOldFavorites(Plasmoid.configuration.favoriteApps);
}
Plasmoid.configuration.favoritesPortedToKAstats = true;
}
}
}
Connections {
target: globalFavorites
function onFavoritesChanged() {
Plasmoid.configuration.favoriteApps = target.favorites;
}
}
Connections {
target: systemFavorites
function onFavoritesChanged() {
Plasmoid.configuration.favoriteSystemActions = target.favorites;
}
}
Connections {
target: Plasmoid.configuration
function onFavoriteAppsChanged() {
globalFavorites.favorites = Plasmoid.configuration.favoriteApps;
}
function onFavoriteSystemActionsChanged() {
systemFavorites.favorites = Plasmoid.configuration.favoriteSystemActions;
}
}
P5Support.DataSource {
id: pmEngine
engine: "powermanagement"
connectedSources: ["PowerDevil", "Sleep States"]
function performOperation(what) {
var service = serviceForSource("PowerDevil")
var operation = service.operationDescription(what)
service.startOperationCall(operation)
}
}
Kicker.RunnerModel {
id: runnerModel
appletInterface: kicker
favoritesModel: globalFavorites
mergeResults: true
runners: {
const results = ["krunner_services", "krunner_systemsettings"];
if (kicker.isDash) {
results.push("krunner_sessions", "krunner_powerdevil", "calculator", "unitconverter");
}
if (Plasmoid.configuration.useExtraRunners) {
results.push(...Plasmoid.configuration.extraRunners);
}
return results;
}
}
Kicker.DragHelper {
id: dragHelper
dragIconSize: Kirigami.Units.iconSizes.medium
}
Kicker.ProcessRunner {
id: processRunner
}
Kicker.WindowSystem {
id: windowSystem
}
KSvg.FrameSvgItem {
id: highlightItemSvg
visible: false
imagePath: "widgets/viewitem"
prefix: "hover"
}
KSvg.FrameSvgItem {
id: listItemSvg
visible: false
imagePath: "widgets/listitem"
prefix: "normal"
}
KSvg.Svg {
id: lineSvg
imagePath: "widgets/line"
property int horLineHeight
property int vertLineWidth
}
PlasmaComponents3.Label {
id: toolTipDelegate
width: contentWidth
height: undefined
font.pointSize: Kirigami.Theme.defaultFont.pointSize + 0.5
property Item toolTip
text: toolTip ? toolTip.text : ""
}
Timer {
id: justOpenedTimer
repeat: false
interval: 600
}
Connections {
target: kicker
function onExpandedChanged(expanded) {
if (expanded) {
windowSystem.monitorWindowVisibility(Plasmoid.fullRepresentationItem);
justOpenedTimer.start();
} else {
kicker.reset();
}
}
}
function resetDragSource() {
dragSource = null;
}
function enableHideOnWindowDeactivate() {
kicker.hideOnWindowDeactivate = true;
}
Plasmoid.contextualActions: [
PlasmaCore.Action {
text: i18n("Edit Applications…")
icon.name: "kmenuedit"
visible: Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable
onTriggered: processRunner.runMenuEditor()
}
]
Component.onCompleted: {
if (Plasmoid.hasOwnProperty("activationTogglesExpanded")) {
Plasmoid.activationTogglesExpanded = !kicker.isDash
}
windowSystem.focusIn.connect(enableHideOnWindowDeactivate);
kicker.hideOnWindowDeactivate = true;
updateSvgMetrics();
PlasmaCore.Theme.themeChanged.connect(updateSvgMetrics);
rootModel.refreshed.connect(reset);
dragHelper.dropped.connect(resetDragSource);
}
}