aerothemeplasma/plasma/plasmoids/org.kde.desktopcontainment/contents/ui/FolderItemDelegate.qml

518 lines
19 KiB
QML
Raw Normal View History

/*
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
SPDX-License-Identifier: GPL-2.0-or-later
*/
2024-08-09 01:20:25 +00:00
import QtQuick 2.15
import QtQuick.Window 2.15
import Qt5Compat.GraphicalEffects
import org.kde.plasma.plasmoid 2.0
2024-08-09 01:20:25 +00:00
import org.kde.plasma.core as PlasmaCore
import org.kde.plasma.extras as PlasmaExtras
import org.kde.plasma.components as PlasmaComponents
2024-08-09 01:20:25 +00:00
import org.kde.kirigami 2.20 as Kirigami
import org.kde.ksvg 1.0 as KSvg
import org.kde.kquickcontrolsaddons 2.0
Item {
id: main
2024-08-09 01:20:25 +00:00
property int index: model.index
property string name: model.blank ? "" : model.display
property string nameWrapped: model.blank ? "" : model.displayWrapped
2024-08-09 01:20:25 +00:00
property bool blank: model.blank
property bool isDir: loader.item ? loader.item.isDir : false
property QtObject popupDialog: loader.item ? loader.item.popupDialog : null
property Item iconArea: loader.item ? loader.item.iconArea : null
property Item label: loader.item ? loader.item.label : null
property Item labelArea: loader.item ? loader.item.labelArea : null
property Item actionsOverlay: loader.item ? loader.item.actionsOverlay : null
property Item hoverArea: loader.item ? loader.item.hoverArea : null
property Item frame: loader.item ? loader.item.frame : null
property Item toolTip: loader.item ? loader.item.toolTip : null
Accessible.name: name
Accessible.role: Accessible.Canvas
2024-08-09 01:20:25 +00:00
// This MouseArea exists to intercept press and hold; preventing edit mode
// from being triggered when pressing and holding on an icon (if there is one).
MouseArea {
anchors.fill: parent
visible: !main.blank
}
function openPopup() {
if (isDir) {
loader.item.openPopup();
}
}
function closePopup() {
if (popupDialog) {
popupDialog.requestDestroy();
loader.item.popupDialog = null;
}
}
Loader {
id: loader
// On the desktop we pad our cellSize to avoid a gap at the right/bottom of the screen.
// The padding per item is quite small and causes the delegate to be positioned on fractional pixels
// leading to blurry rendering. The Loader is offset to account for this.
x: -main.x % 1
y: -main.y % 1
width: parent.width
height: parent.height
visible: status === Loader.Ready
active: !model.blank
sourceComponent: delegateImplementation
asynchronous: true
}
Component {
id: delegateImplementation
Item {
id: impl
anchors.fill: parent
property bool blank: model.blank
property bool selected: model.blank ? false : model.selected
property bool isDir: model.blank ? false : model.isDir
property bool hovered: (main.GridView.view.hoveredItem === main)
property QtObject popupDialog: null
property Item iconArea: icon
property Item label: label
2024-08-09 01:20:25 +00:00
property Item labelArea: label
property Item actionsOverlay: actions
property Item hoverArea: toolTip
property Item frame: frameLoader
property Item toolTip: toolTip
property Item selectionButton: null
property Item popupButton: null
2024-08-09 01:20:25 +00:00
readonly property bool iconAndLabelsShouldlookSelected: impl.hovered
// When a drop happens, a new item is created, and is set to selected
// grabToImagebefore it gets the final width, making grabToImage fail because it's still 0x0
onSelectedChanged: Qt.callLater(updateDragImage)
function updateDragImage() {
if (selected && !blank) {
2024-08-09 01:20:25 +00:00
frameLoader.grabToImage(result => {
dir.addItemDragImage(positioner.map(index), main.x + frameLoader.x, main.y + frameLoader.y, frameLoader.width, frameLoader.height, result.image);
});
}
}
Connections {
target: model
function onSelectedChanged() {
if (dir.usedByContainment && model.selected) {
gridView.currentIndex = model.index;
}
}
}
onHoveredChanged: {
if (hovered) {
2024-08-09 01:20:25 +00:00
// In list view, it behaves more like a menu, and menus always activate their items on a single click
if (Plasmoid.configuration.selectionMarkers && (Qt.styleHints.singleClickActivation || root.useListViewMode)) {
selectionButton = selectionButtonComponent.createObject(actions);
}
if (model.isDir) {
if (!main.GridView.view.isRootView || root.containsDrag) {
hoverActivateTimer.restart();
}
2024-08-09 01:20:25 +00:00
if (Plasmoid.configuration.popups && !root.useListViewMode) {
popupButton = popupButtonComponent.createObject(actions);
}
}
} else if (!hovered) {
if (popupDialog != null) {
closePopup();
}
if (selectionButton) {
selectionButton.destroy();
selectionButton = null;
}
if (popupButton) {
popupButton.destroy();
popupButton = null;
}
}
}
function openPopup() {
2024-08-09 01:20:25 +00:00
if (folderViewDialogComponent.status === Component.Ready) {
impl.popupDialog = folderViewDialogComponent.createObject(impl);
impl.popupDialog.visualParent = icon;
impl.popupDialog.url = model.linkDestinationUrl;
impl.popupDialog.visible = true;
}
}
PlasmaCore.ToolTipArea {
id: toolTip
2024-08-09 01:20:25 +00:00
active: (Plasmoid.configuration.toolTips || label.truncated)
&& popupDialog === null
&& !model.blank
interactive: false
2024-08-09 01:20:25 +00:00
location: root.useListViewMode ? (Plasmoid.location === PlasmaCore.Types.LeftEdge ? PlasmaCore.Types.LeftEdge : PlasmaCore.Types.RightEdge) : Plasmoid.location
z: 999
//anchors.fill: parent
MouseArea {
id: ma
anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
onPositionChanged: (mouse) => {
if (containsMouse && !model.blank) {
if (toolTip.active) {
toolTip.textFormat = Text.RichText;
toolTip.mainText = model.display;
if (model.size !== undefined) {
2023-08-24 22:32:11 +00:00
toolTip.subText = model.type + "<br>" + "Size: " + model.size;
2024-08-09 01:20:25 +00:00
} else {
toolTip.subText = model.type;
}
}
2024-08-09 01:20:25 +00:00
main.GridView.view.hoveredItem = main;
}
2024-08-09 01:20:25 +00:00
mouse.accepted = false;
}
}
2024-08-09 01:20:25 +00:00
states: [
State { // icon view
when: !root.useListViewMode
AnchorChanges {
target: toolTip
anchors.horizontalCenter: parent.horizontalCenter
}
PropertyChanges {
target: toolTip
2024-08-09 01:20:25 +00:00
x: Kirigami.Units.smallSpacing
y: Kirigami.Units.smallSpacing
width: parent.width - Kirigami.Units.smallSpacing
height: parent.height - Kirigami.Units.smallSpacing
//width: Math.max(icon.paintedWidth, label.paintedWidth)
//height: (label.y + label.paintedHeight)
//y: frameLoader.y + icon.y
//width: Math.max(icon.paintedWidth, label.paintedWidth)
//height: (label.y + label.paintedHeight) - y
}
},
State { // list view
when: root.useListViewMode
AnchorChanges {
target: toolTip
anchors.horizontalCenter: undefined
}
PropertyChanges {
target: toolTip
x: frameLoader.x
y: frameLoader.y
width: frameLoader.width
height: frameLoader.height
}
}
]
}
Loader {
id: frameLoader
2024-08-09 01:20:25 +00:00
x: 0//root.useListViewMode ? 0 : Kirigami.Units.smallSpacing
y: root.useListViewMode ? 0 : Kirigami.Units.smallSpacing
property Item iconShadow: null
property string prefix: ""
sourceComponent: frameComponent
2024-08-09 01:20:25 +00:00
active: impl.iconAndLabelsShouldlookSelected || model.selected
asynchronous: true
width: {
if (root.useListViewMode) {
if (main.GridView.view.overflowing) {
2024-08-09 01:20:25 +00:00
return parent.width// - Kirigami.Units.smallSpacing;
} else {
return parent.width;
}
}
2024-08-09 01:20:25 +00:00
return parent.width// - (Kirigami.Units.smallSpacing * 2);
}
2024-08-09 01:20:25 +00:00
height: root.useListViewMode
? parent.height
// the smallSpacings are for padding
: icon.height + (Kirigami.Units.iconSizes.small * label.lineCount) + (Kirigami.Units.smallSpacing * 3)
2024-08-09 01:20:25 +00:00
Kirigami.Icon {
id: icon
z: 2
states: [
State { // icon view
when: !root.useListViewMode
AnchorChanges {
target: icon
anchors.top: parent.top
anchors.horizontalCenter: parent.horizontalCenter
}
},
State { // list view
when: root.useListViewMode
AnchorChanges {
target: icon
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
}
}
]
anchors {
2024-08-09 01:20:25 +00:00
topMargin: Kirigami.Units.smallSpacing
leftMargin: Kirigami.Units.smallSpacing
}
2024-08-09 01:20:25 +00:00
width: root.useListViewMode ? main.GridView.view.iconSize : (parent.width - 2 * Kirigami.Units.smallSpacing)
height: main.GridView.view.iconSize
opacity: {
if (root.useListViewMode && selectionButton) {
return 0.3;
}
if (model.isHidden) {
return 0.6;
}
return 1.0;
}
animated: false
source: model.decoration
}
PlasmaComponents.Label {
id: label
2024-08-09 01:20:25 +00:00
z: 2 // So it's always above the highlight effect
states: [
State { // icon view
when: !root.useListViewMode
AnchorChanges {
target: label
anchors.top: icon.bottom
anchors.horizontalCenter: parent.horizontalCenter
}
PropertyChanges {
target: label
2024-08-09 01:20:25 +00:00
anchors.topMargin: Kirigami.Units.smallSpacing
width: parent.width - Kirigami.Units.smallSpacing
maximumLineCount: Plasmoid.configuration.textLines
horizontalAlignment: Text.AlignHCenter
}
},
State { // list view
when: root.useListViewMode
AnchorChanges {
target: label
anchors.left: icon.right
anchors.verticalCenter: parent.verticalCenter
}
PropertyChanges {
target: label
2024-08-09 01:20:25 +00:00
anchors.leftMargin: Kirigami.Units.smallSpacing * 2
anchors.rightMargin: Kirigami.Units.smallSpacing * 2
width: parent.width - icon.width - (Kirigami.Units.smallSpacing * 4)
maximumLineCount: 1
horizontalAlignment: Text.AlignLeft
}
}
]
2024-08-09 01:20:25 +00:00
color: {
if (Plasmoid.isContainment) {
// In this situation there's a shadow or a background rect, both of which are always black
return "white";
}
2024-08-09 01:20:25 +00:00
if (model.selected) {
return Kirigami.Theme.highlightedTextColor;
}
2024-08-09 01:20:25 +00:00
return Kirigami.Theme.textColor;
}
2024-08-09 01:20:25 +00:00
//renderShadow: false //(Plasmoid.isContainment && (!editor || editor.targetItem !== main)) && Plasmoid.configuration.textShadows
opacity: model.isHidden ? 0.6 : 1
text: main.nameWrapped
2024-08-09 01:20:25 +00:00
elide: Text.ElideRight
2024-01-20 02:08:06 +00:00
//font.italic: model.isLink
2024-08-09 01:20:25 +00:00
wrapMode: (maximumLineCount === 1) ? Text.NoWrap : Text.Wrap
horizontalAlignment: Text.AlignHCenter
2024-08-09 01:20:25 +00:00
layer.enabled: true
layer.effect: DropShadow {
anchors.fill: label
2024-08-09 01:20:25 +00:00
z: 1
2024-08-09 01:20:25 +00:00
horizontalOffset: 1
verticalOffset: 1
radius: 3.0
samples: radius * 2
spread: 0.435
color: "#F9080808"
opacity: model.isHidden ? 0.6 : 1
source: label
visible: (Plasmoid.isContainment && (!editor || editor.targetItem !== main)) && Plasmoid.configuration.textShadows
}
}
Component {
id: frameComponent
2024-08-09 01:20:25 +00:00
PlasmaExtras.Highlight {
// Workaround for a bug where the frameComponent does not
// get unloaded when items are dragged to a different
// place on the desktop.
visible: this === frameLoader.item
2024-08-09 01:20:25 +00:00
hovered: impl.iconAndLabelsShouldlookSelected
pressed: model.selected
active: Window.active
}
}
Component {
id: selectionButtonComponent
FolderItemActionButton {
element: model.selected ? "remove" : "add"
onClicked: {
2024-08-09 01:20:25 +00:00
dir.toggleSelected(positioner.map(index));
main.GridView.view.currentIndex = index;
}
}
}
Component {
id: popupButtonComponent
FolderItemActionButton {
visible: main.GridView.view.isRootView && (popupDialog == null)
element: "open"
onClicked: {
2024-08-09 01:20:25 +00:00
dir.setSelected(positioner.map(index));
main.GridView.view.currentIndex = index;
openPopup();
}
}
}
Component {
id: iconShadowComponent
DropShadow {
anchors.fill: icon
z: 1
verticalOffset: 1
2024-08-09 01:20:25 +00:00
radius: 5.0
samples: radius * 2 + 1
spread: 0.05
color: "black"
opacity: model.isHidden ? 0.3 : 0.6
2024-08-09 01:20:25 +00:00
visible: Plasmoid.configuration.iconShadows
source: icon
}
}
}
Column {
id: actions
visible: {
if (main.GridView.view.isRootView && root.containsDrag) {
return false;
}
if (!main.GridView.view.isRootView && main.GridView.view.dialog && main.GridView.view.dialog.containsDrag) {
return false;
}
if (popupDialog) {
return false;
}
return true;
}
anchors {
left: frameLoader.left
top: frameLoader.top
leftMargin: root.useListViewMode ? (icon.x + (icon.width / 2)) - (width / 2) : 0
2024-08-09 01:20:25 +00:00
topMargin: root.useListViewMode ? (icon.y + (icon.height / 2)) - (height / 2) : 0
}
width: implicitWidth
height: implicitHeight
}
Component.onCompleted: {
2024-08-09 01:20:25 +00:00
if (Plasmoid.isContainment && main.GridView.view.isRootView && root.GraphicsInfo.api === GraphicsInfo.OpenGL) {
frameLoader.iconShadow = iconShadowComponent.createObject(frameLoader);
}
}
}
}
}