Skip to content

Commit

Permalink
port to plasma 6
Browse files Browse the repository at this point in the history
  • Loading branch information
HimDek committed Dec 22, 2023
1 parent 87ada5c commit 68014ec
Show file tree
Hide file tree
Showing 25 changed files with 1,734 additions and 997 deletions.
36 changes: 20 additions & 16 deletions contents/config/main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,22 @@
<group name="General">
<entry name="icon" type="String">
<label>The name of the icon used in the compact representation (e.g. on a small panel).</label>
<default>start-here-kde</default>
<default>start-here-kde-symbolic</default>
</entry>
<entry name="menuLabel" type="string">
<label>Text label for the Panel button</label>
<default></default>
</entry>
<entry name="favorites" type="StringList">
<label>List of general favorites. Supported values are menu id's (usually .desktop file names), special URLs that expand into default applications (e.g. preferred://browser), document URLs and KPeople contact URIs.</label>
<default>preferred://browser,org.kde.kontact.desktop,systemsettings.desktop,org.kde.dolphin.desktop,ktp-contactlist.desktop,org.kde.discover.desktop</default>
<default>preferred://browser,org.kde.kontact.desktop,systemsettings.desktop,org.kde.dolphin.desktop,org.kde.discover.desktop</default>
</entry>
<entry name="systemFavorites" type="StringList">
<label>List of system action favorites.</label>
<default>suspend,hibernate,reboot,shutdown</default>
</entry>
<entry name="gridColumns" type="Int">
<label>Number of cloumns in the grid</label>
<default>4</default>
</entry>
<entry name="gridRows" type="Int">
<label>Number of rows in the grid</label>
<default>4</default>
</entry>
<entry name="hoverActivate" type="Bool">
<label>Whether to activate or change categories on hover</label>
<default>true</default>
</entry>
<entry name="primaryActions" type="Int">
<label>Which actions should be displayed in the header: 0 = Power, 1 = Session, 2 = Custom, 3 = Power and session</label>
<label>Which actions should be displayed in the footer: 0 = Power, 1 = Session, 2 = Custom, 3 = Power and session</label>
<default>0</default>
</entry>
<entry name="favoritesPortedToKAstats" type="Bool">
Expand All @@ -41,6 +33,10 @@
<label>List of applications at the top of the "Computer" tab.</label>
<default>systemsettings.desktop,org.kde.kinfocenter.desktop,org.kde.discover.desktop</default>
</entry>
<entry name="paneSwap" type="Bool">
<label>Whether to swap the sidebar and content panes</label>
<default>false</default>
</entry>
<entry name="favoritesDisplay" type="Int">
<label>How to display favorites: 0 = Grid, 1 = List</label>
<default>0</default>
Expand All @@ -51,11 +47,19 @@
</entry>
<entry name="alphaSort" type="Bool">
<label>Whether to sort menu contents alphabetically or use manual/system sort order.</label>
<default>true</default>
<default>false</default>
</entry>
<entry name="pin" type="Bool">
<label>Whether the popup should remain open when another window is activated</label>
<default>false</default>
</entry>
<entry name="showActionButtonCaptions" type="Bool">
<label>Whether to display captions ("shut down", "log out", etc.) for the action buttons</label>
<default>true</default>
</entry>
<entry name="compactMode" type="Bool">
<label>Whether to use a compact display style for list items</label>
<default>false</default>
</entry>
</group>
</kcfg>
227 changes: 227 additions & 0 deletions contents/ui/AbstractKickoffItemDelegate.qml
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
/*
SPDX-FileCopyrightText: 2011 Martin Gräßlin <[email protected]>
SPDX-FileCopyrightText: 2012 Gregor Taetzner <[email protected]>
SPDX-FileCopyrightText: 2014 Sebastian Kügler <[email protected]>
SPDX-FileCopyrightText: 2015-2018 Eike Hein <[email protected]>
SPDX-FileCopyrightText: 2021 Mikel Johnson <[email protected]>
SPDX-FileCopyrightText: 2021 Noah Davis <[email protected]>
SPDX-FileCopyrightText: 2022 Nate Graham <[email protected]>
SPDX-License-Identifier: GPL-2.0-or-later
*/
import QtQuick 2.15
import QtQml 2.15
import QtQuick.Layouts 1.15
import QtQuick.Templates 2.15 as T
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.components 3.0 as PC3
import org.kde.kirigami 2.20 as Kirigami
import "code/tools.js" as Tools
import org.kde.plasma.plasmoid 2.0

T.ItemDelegate {
id: root

// model properties
required property var model
required property int index
required property url url
required property var decoration
required property string description

readonly property Flickable view: ListView.view ?? GridView.view
property bool isCategoryListItem: false
readonly property bool hasActionList: model && (model.favoriteId !== null || ("hasActionList" in model && model.hasActionList === true))
property bool isSearchResult: false

readonly property bool isSeparator: model && (model.isSeparator === true)
property int separatorHeight: KickoffSingleton.lineSvg.horLineHeight + (2 * Kirigami.Units.smallSpacing)
property int itemHeight: Math.max(implicitBackgroundHeight + topInset + bottomInset, implicitContentHeight + topPadding + bottomPadding)

readonly property bool dragEnabled: enabled && !isCategoryListItem
&& Plasmoid.immutability !== PlasmaCore.Types.SystemImmutable

readonly property alias mouseArea: mouseArea

readonly property bool iconAndLabelsShouldlookSelected: isPressed && !isCategoryListItem

property bool labelTruncated: false
property bool descriptionTruncated: false
property bool descriptionVisible: true

property Item dragIconItem: null

// pressed: is read-only and we're not using it here because we have fancy
// custom mouse handling
readonly property bool isPressed: mouseArea.pressed

function openActionMenu(x = undefined, y = undefined) {
if (!hasActionList) { return; }

let actions = model.actionList;
const favoriteActions = Tools.createFavoriteActions(
i18n, //i18n() function callback
view.model.favoritesModel,
model.favoriteId,
);
if (favoriteActions) {
if (actions && actions.length > 0) {
actions.push({ "type": "separator" }, ...favoriteActions);
} else {
actions = favoriteActions;
}
}

if (actions && actions.length > 0) {
ActionMenu.plasmoid = kickoff;
ActionMenu.menu.visualParent = root;
ActionMenu.actionList = actions;
if (x !== undefined && y !== undefined) {
ActionMenu.menu.open(x, y);
} else {
ActionMenu.menu.openRelative();
}
}
}

// The default Z value for delegates is 1. The default Z value for the section delegate is 2.
// The highlight gets a value of 3 while the drag is active and then goes back to the default value of 0.
z: Drag.active ? 4 : 1

implicitWidth: Math.max(implicitBackgroundWidth + leftInset + rightInset,
implicitContentWidth + leftPadding + rightPadding)
implicitHeight: isSeparator ? separatorHeight : itemHeight

spacing: KickoffSingleton.fontMetrics.descent

enabled: !isSeparator && !model.disabled
hoverEnabled: false

text: model.name ?? model.displayWrapped ?? model.display
Accessible.role: Accessible.ListItem
Accessible.description: root.description !== root.text ? root.description : ""
Accessible.onPressAction: {
root.forceActiveFocus() // trigger is focus guarded
action.trigger()
}

// Using an action so that it can be replaced or manually triggered
// using `model` () instead of `root.model` leads to errors about
// `model` not having the trigger() function
action: T.Action {
onTriggered: {
// Unless we're showing search results, eat the activation if we
// don't have focus, to prevent the return/enter key from
// inappropriately activating unfocused items
if (!root.activeFocus && !root.isSearchResult) {
return;
}
view.currentIndex = index
// if successfully triggered, close popup
if (view.model.trigger && view.model.trigger(index, "", null)) {
if (kickoff.hideOnWindowDeactivate) {
kickoff.expanded = false;
}
}
}
}

Drag.active: mouseArea.drag.active
Drag.dragType: Drag.Automatic
Drag.mimeData: { "text/uri-list" : root.url }
Drag.onDragFinished: Drag.imageSource = ""

MouseArea {
id: mouseArea
property bool dragEnabled: false
parent: root
anchors.fill: parent
anchors.margins: 1
// Flickable margins are not mirrored, so disable layout mirroring
LayoutMirroring.enabled: false
// Only for ListView since extending margins for GridView is hard
anchors.leftMargin: root.view instanceof ListView ? -root.view.leftMargin : anchors.margins
anchors.rightMargin: root.view instanceof ListView ? -root.view.rightMargin : anchors.margins
hoverEnabled: root.view
// When the movedWithWheel condition is broken, this ensures that
// onEntered is called again without moving the mouse.
&& !root.view.movedWithWheel
// Fix VerticalStackView animation causing view currentIndex
// to change while delegates are moving under the mouse cursor
&& kickoff.fullRepresentationItem && !kickoff.fullRepresentationItem.contentItem.busy && !kickoff.fullRepresentationItem.blockingHoverFocus
acceptedButtons: Qt.LeftButton | Qt.RightButton
drag {
axis: Drag.XAndYAxis
target: root.dragEnabled && mouseArea.dragEnabled ? dragItem : undefined
}
// Using this Item fixes drag and drop causing delegates
// to reset to a 0 X position and overlapping each other.
Item { id: dragItem }

onEntered: {
// When the movedWithKeyboard condition is broken, we do not want to
// select the hovered item without moving the mouse.
if (root.view.movedWithKeyboard) {
return
}
// Don't highlight separators.
if (root.isSeparator) {
return;
}

// forceActiveFocus() touches multiple items, so check for
// activeFocus first to be more efficient.
if (!root.activeFocus) {
root.forceActiveFocus(Qt.MouseFocusReason)
}
// No need to check currentIndex first because it's
// built into QQuickListView::setCurrentIndex() already
root.view.currentIndex = index
}
onPressed: mouse => {
// Select and focus on press to improve responsiveness and touch feedback
view.currentIndex = index
root.forceActiveFocus(Qt.MouseFocusReason)

// Only enable drag and drop with a mouse.
// We don't have a good way to handle it and drag scrolling with touch.
mouseArea.dragEnabled = mouse.source === Qt.MouseEventNotSynthesized

// We normally try to open right click menus on press like Qt Widgets
if (mouse.button === Qt.RightButton) {
root.openActionMenu(mouseX, mouseY)
} else if (mouseArea.dragEnabled && mouse.button === Qt.LeftButton
&& root.dragEnabled && root.dragIconItem && root.Drag.imageSource.toString() === ""
) {
root.dragIconItem.grabToImage(result => {
root.Drag.imageSource = result.url
})
}
}
onClicked: mouse => {
if (mouse.button === Qt.LeftButton) {
root.action.trigger()
}
}
// MouseEvents for pressAndHold use Qt.MouseEventSynthesizedByQt for mouse.source,
// which makes checking mouse.source for whether or not touch input is used useless.
onPressAndHold: mouse => {
if (mouse.button === Qt.LeftButton) {
root.openActionMenu(mouseX, mouseY)
}
}
}

PC3.ToolTip.text: {
if (root.labelTruncated && root.descriptionTruncated) {
return `${text} (${description})`
} else if (root.descriptionTruncated || !root.descriptionVisible) {
return description
}
return ""
}
PC3.ToolTip.visible: mouseArea.containsMouse && PC3.ToolTip.text.length > 0
PC3.ToolTip.delay: Kirigami.Units.toolTipDelay

background: null
}
51 changes: 28 additions & 23 deletions contents/ui/ActionMenu.qml
Original file line number Diff line number Diff line change
Expand Up @@ -10,48 +10,53 @@
pragma Singleton // NOTE: Singletons are shared between all instances of a plasmoid

import QtQuick 2.15
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.components 2.0 as PC2 // for Menu + MenuItem
import org.kde.plasma.extras 2.0 as PlasmaExtras
import "code/tools.js" as Tools

Item {
id: root
property var actionList: menu.visualParent ? menu.visualParent.actionList : null

// Workaround for `plasmoid` context property not working in singletons.
property var actionList: null

// Only one action menu can be open at a time, so this should be safe to use.
property Plasmoid plasmoid: null
property PlasmoidItem plasmoid: null

// Not a QQC1 Menu. It's actually a custom QObject that uses a QMenu.
readonly property PC2.Menu menu: PC2.Menu {
readonly property PlasmaExtras.Menu menu: PlasmaExtras.Menu {
id: menu

visualParent: null
placement: PlasmaCore.Types.BottomPosedLeftAlignedPopup
placement: PlasmaExtras.Menu.BottomPosedLeftAlignedPopup
}

visible: false

Instantiator {
active: actionList != null
model: actionList
active: root.actionList !== null
model: root.actionList
delegate: menuItemComponent
onObjectAdded: menu.addMenuItem(object)
onObjectRemoved: menu.removeMenuItem(object)
onObjectAdded: (index, object) => menu.addMenuItem(object)
onObjectRemoved: (index, object) => menu.removeMenuItem(object)
}

Component { id: menuComponent; PC2.Menu {} }
Component {
id: menuComponent

PlasmaExtras.Menu {}
}

Component {
id: menuItemComponent
PC2.MenuItem {

PlasmaExtras.MenuItem {
id: menuItem

required property var modelData
property PC2.Menu subMenu: if (modelData.subActions) {
return menuComponent.createObject(menuItem, {visualParent: menuItem.action})
} else {
return null
}
property PlasmaExtras.Menu subMenu: modelData.subActions
? menuComponent.createObject(menuItem, { visualParent: menuItem.action })
: null

text: modelData.text ? modelData.text : ""
enabled: modelData.type !== "title" && ("enabled" in modelData ? modelData.enabled : true)
Expand All @@ -61,12 +66,12 @@ Item {
checkable: modelData.hasOwnProperty("checkable") ? modelData.checkable : false
checked: modelData.hasOwnProperty("checked") ? modelData.checked : false

Instantiator {
active: menuItem.subMenu != null
property Instantiator _instantiator: Instantiator {
active: menuItem.subMenu !== null
model: modelData.subActions
delegate: menuItemComponent
onObjectAdded: subMenu.addMenuItem(object)
onObjectRemoved: subMenu.removeMenuItem(object)
onObjectAdded: (index, object) => subMenu.addMenuItem(object)
onObjectRemoved: (index, object) => subMenu.removeMenuItem(object)
}

onClicked: {
Expand All @@ -77,7 +82,7 @@ Item {
modelData.actionArgument
)
if (modelActionTriggered) {
root.plasmoid.expanded = false
kickoff.expanded = false
}
}
}
Expand Down
Loading

0 comments on commit 68014ec

Please sign in to comment.