2022-08-28 21:48:51 +00:00
|
|
|
/*
|
|
|
|
SPDX-FileCopyrightText: 2014-2015 Eike Hein <hein@kde.org>
|
|
|
|
|
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
|
|
|
|
|
|
|
import QtQuick 2.8
|
|
|
|
import QtQuick.Window 2.2
|
|
|
|
import QtGraphicalEffects 1.0
|
|
|
|
|
|
|
|
import org.kde.plasma.plasmoid 2.0
|
|
|
|
|
|
|
|
import org.kde.plasma.core 2.0 as PlasmaCore
|
|
|
|
import org.kde.plasma.components 2.0 as PlasmaComponents
|
|
|
|
import org.kde.kquickcontrolsaddons 2.0
|
|
|
|
|
|
|
|
Item {
|
|
|
|
id: main
|
|
|
|
|
|
|
|
property int index: model.index
|
|
|
|
property string name: model.blank ? "" : model.display
|
|
|
|
property string nameWrapped: model.blank ? "" : model.displayWrapped
|
|
|
|
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
|
|
|
|
|
|
|
|
MouseArea { anchors.fill: parent } // This MouseArea exists to intercept press and hold;
|
|
|
|
// preventing edit mode from being triggered
|
|
|
|
// when pressing and holding on an icon
|
|
|
|
|
|
|
|
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
|
|
|
|
property Item labelArea: frameLoader.textShadow || 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
|
|
|
|
|
|
|
|
onSelectedChanged: {
|
|
|
|
if (selected && !blank) {
|
|
|
|
frameLoader.grabToImage(function(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) {
|
|
|
|
if (plasmoid.configuration.selectionMarkers && Qt.styleHints.singleClickActivation) {
|
|
|
|
selectionButton = selectionButtonComponent.createObject(actions);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (model.isDir) {
|
|
|
|
if (!main.GridView.view.isRootView || root.containsDrag) {
|
|
|
|
hoverActivateTimer.restart();
|
|
|
|
}
|
|
|
|
|
|
|
|
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() {
|
|
|
|
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
|
|
|
|
|
|
|
|
active: (plasmoid.configuration.toolTips && popupDialog == null && !model.blank)
|
|
|
|
interactive: false
|
|
|
|
location: root.useListViewMode ? (plasmoid.location === PlasmaCore.Types.LeftEdge ? PlasmaCore.Types.LeftEdge : PlasmaCore.Types.RightEdge) : plasmoid.location
|
|
|
|
|
2023-08-24 22:32:11 +00:00
|
|
|
|
2022-08-28 21:48:51 +00:00
|
|
|
onContainsMouseChanged: {
|
|
|
|
if (containsMouse && !model.blank) {
|
|
|
|
if (toolTip.active) {
|
2023-08-24 22:32:11 +00:00
|
|
|
//toolTip.icon = model.decoration;
|
|
|
|
|
|
|
|
toolTip.textFormat = Text.RichText;
|
2022-08-28 21:48:51 +00:00
|
|
|
toolTip.mainText = model.display;
|
|
|
|
|
|
|
|
if (model.size !== undefined) {
|
2023-08-24 22:32:11 +00:00
|
|
|
toolTip.subText = model.type + "<br>" + "Size: " + model.size;
|
2022-08-28 21:48:51 +00:00
|
|
|
} else {
|
|
|
|
toolTip.subText = model.type;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
main.GridView.view.hoveredItem = main;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
states: [
|
|
|
|
State { // icon view
|
|
|
|
when: !root.useListViewMode
|
|
|
|
|
|
|
|
AnchorChanges {
|
|
|
|
target: toolTip
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
}
|
|
|
|
|
|
|
|
PropertyChanges {
|
|
|
|
target: toolTip
|
|
|
|
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
|
|
|
|
|
|
|
|
x: root.useListViewMode ? 0 : PlasmaCore.Units.smallSpacing
|
|
|
|
y: root.useListViewMode ? 0 : PlasmaCore.Units.smallSpacing
|
|
|
|
|
|
|
|
property Item textShadow: null
|
|
|
|
property Item iconShadow: null
|
|
|
|
property string prefix: ""
|
|
|
|
|
|
|
|
sourceComponent: frameComponent
|
|
|
|
active: state !== ""
|
|
|
|
asynchronous: true
|
|
|
|
|
|
|
|
width: {
|
|
|
|
if (root.useListViewMode) {
|
|
|
|
if (main.GridView.view.overflowing) {
|
|
|
|
return parent.width - PlasmaCore.Units.smallSpacing;
|
|
|
|
} else {
|
|
|
|
return parent.width;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return parent.width - (PlasmaCore.Units.smallSpacing * 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
height: {
|
|
|
|
if (root.useListViewMode) {
|
|
|
|
return parent.height;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Note: frameLoader.y = PlasmaCore.Units.smallSpacing (acts as top margin)
|
|
|
|
return (PlasmaCore.Units.smallSpacing // icon.anchors.topMargin (acts as top padding)
|
|
|
|
+ icon.height
|
|
|
|
+ PlasmaCore.Units.smallSpacing // label.anchors.topMargin (acts as spacing between icon and label)
|
|
|
|
+ (label.lineCount * PlasmaCore.Theme.mSize(PlasmaCore.Theme.defaultFont).height)
|
|
|
|
+ PlasmaCore.Units.smallSpacing); // leftover (acts as bottom padding)
|
|
|
|
}
|
|
|
|
|
|
|
|
PlasmaCore.IconItem {
|
|
|
|
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 {
|
|
|
|
topMargin: PlasmaCore.Units.smallSpacing
|
|
|
|
leftMargin: PlasmaCore.Units.smallSpacing
|
|
|
|
}
|
|
|
|
|
|
|
|
width: root.useListViewMode ? main.GridView.view.iconSize : (parent.width - 2 * PlasmaCore.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
|
|
|
|
usesPlasmaTheme: false
|
|
|
|
|
|
|
|
smooth: true
|
|
|
|
|
|
|
|
source: model.decoration
|
|
|
|
}
|
|
|
|
|
|
|
|
Rectangle {
|
|
|
|
id: fallbackRectangleBackground
|
|
|
|
visible: GraphicsInfo.api === GraphicsInfo.Software && !model.selected
|
|
|
|
anchors {
|
|
|
|
fill: label
|
|
|
|
margins: -PlasmaCore.Units.smallSpacing
|
|
|
|
}
|
|
|
|
|
|
|
|
color: "black"
|
|
|
|
radius: PlasmaCore.Units.smallSpacing
|
|
|
|
opacity: 0.45
|
|
|
|
}
|
|
|
|
|
|
|
|
PlasmaComponents.Label {
|
|
|
|
id: label
|
|
|
|
|
|
|
|
z: 2 // So we can position a textShadowComponent below if needed.
|
|
|
|
|
|
|
|
states: [
|
|
|
|
State { // icon view
|
|
|
|
when: !root.useListViewMode
|
|
|
|
|
|
|
|
AnchorChanges {
|
|
|
|
target: label
|
|
|
|
anchors.top: icon.bottom
|
|
|
|
anchors.horizontalCenter: parent.horizontalCenter
|
|
|
|
}
|
|
|
|
PropertyChanges {
|
|
|
|
target: label
|
|
|
|
anchors.topMargin: PlasmaCore.Units.smallSpacing
|
|
|
|
width: Math.round(Math.min(label.implicitWidth + PlasmaCore.Units.smallSpacing, parent.width - PlasmaCore.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
|
|
|
|
anchors.leftMargin: PlasmaCore.Units.smallSpacing * 2
|
|
|
|
anchors.rightMargin: PlasmaCore.Units.smallSpacing * 2
|
|
|
|
width: parent.width - icon.width - (PlasmaCore.Units.smallSpacing * 4)
|
|
|
|
maximumLineCount: 1
|
|
|
|
horizontalAlignment: Text.AlignLeft
|
|
|
|
}
|
|
|
|
}
|
|
|
|
]
|
|
|
|
|
|
|
|
height: undefined // Unset PlasmaComponents.Label's default.
|
|
|
|
|
|
|
|
textFormat: Text.PlainText
|
|
|
|
|
|
|
|
wrapMode: (maximumLineCount == 1) ? Text.NoWrap : Text.Wrap
|
|
|
|
elide: Text.ElideRight
|
|
|
|
|
|
|
|
color: {
|
|
|
|
if ((frameLoader.textShadow && frameLoader.textShadow.visible) || fallbackRectangleBackground.visible) {
|
|
|
|
return "#fff";
|
|
|
|
} else if (model.selected) {
|
|
|
|
return PlasmaCore.ColorScope.highlightedTextColor;
|
|
|
|
} else {
|
|
|
|
return PlasmaCore.ColorScope.textColor
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
opacity: model.isHidden ? 0.6 : 1
|
|
|
|
|
|
|
|
text: main.nameWrapped
|
|
|
|
|
|
|
|
font.italic: model.isLink
|
|
|
|
|
|
|
|
visible: {
|
|
|
|
if (editor && editor.targetItem === main) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// DropShadow renders the Label already.
|
|
|
|
if (frameLoader.textShadow && frameLoader.textShadow.visible) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: frameComponent
|
|
|
|
|
|
|
|
PlasmaCore.FrameSvgItem {
|
|
|
|
// 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
|
|
|
|
|
|
|
|
prefix: frameLoader.prefix
|
|
|
|
|
2023-08-24 22:32:11 +00:00
|
|
|
imagePath: Qt.resolvedUrl("svgs/viewitem.svg")
|
2022-08-28 21:48:51 +00:00
|
|
|
|
|
|
|
// Use inactive highlight effect when something else has focus
|
|
|
|
opacity: Window.active ? 1 : 0.4
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: selectionButtonComponent
|
|
|
|
|
|
|
|
FolderItemActionButton {
|
|
|
|
element: model.selected ? "remove" : "add"
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
dir.toggleSelected(positioner.map(index))
|
|
|
|
main.GridView.view.currentIndex = index
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: popupButtonComponent
|
|
|
|
|
|
|
|
FolderItemActionButton {
|
|
|
|
visible: main.GridView.view.isRootView && (popupDialog == null)
|
|
|
|
|
|
|
|
element: "open"
|
|
|
|
|
|
|
|
onClicked: {
|
|
|
|
dir.setSelected(positioner.map(index))
|
|
|
|
main.GridView.view.currentIndex = index
|
|
|
|
openPopup();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: iconShadowComponent
|
|
|
|
|
|
|
|
DropShadow {
|
|
|
|
anchors.fill: icon
|
|
|
|
|
|
|
|
z: 1
|
|
|
|
|
|
|
|
verticalOffset: 1
|
|
|
|
|
|
|
|
radius: Math.round(5 * PlasmaCore.Units.devicePixelRatio)
|
|
|
|
samples: radius * 2 + 1
|
|
|
|
spread: 0.05
|
|
|
|
|
|
|
|
color: "black"
|
|
|
|
|
|
|
|
opacity: model.isHidden ? 0.3 : 0.6
|
|
|
|
|
|
|
|
source: icon
|
|
|
|
|
|
|
|
visible: !editor || editor.targetItem != main
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Component {
|
|
|
|
id: textShadowComponent
|
|
|
|
|
|
|
|
DropShadow {
|
|
|
|
anchors.fill: label
|
|
|
|
|
|
|
|
z: 1
|
|
|
|
|
|
|
|
horizontalOffset: 1
|
|
|
|
verticalOffset: 1
|
|
|
|
|
|
|
|
radius: Math.round(4 * PlasmaCore.Units.devicePixelRatio)
|
|
|
|
samples: radius * 2 + 1
|
|
|
|
spread: 0.35
|
|
|
|
|
|
|
|
color: "black"
|
|
|
|
|
|
|
|
opacity: model.isHidden ? 0.6 : 1
|
|
|
|
|
|
|
|
source: label
|
|
|
|
|
|
|
|
visible: !editor || editor.targetItem != main
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
states: [
|
|
|
|
State {
|
|
|
|
name: "selected"
|
|
|
|
when: model.selected && !hovered
|
|
|
|
|
|
|
|
PropertyChanges {
|
|
|
|
target: frameLoader
|
|
|
|
prefix: "selected"
|
|
|
|
}
|
|
|
|
},
|
|
|
|
State {
|
|
|
|
name: "selected+hover"
|
|
|
|
when: hovered && plasmoid.configuration.iconHoverEffect
|
|
|
|
|
|
|
|
PropertyChanges {
|
|
|
|
target: frameLoader
|
|
|
|
prefix: {
|
|
|
|
if(!model.selected) return "hover";
|
|
|
|
if(model.selected) return "selected+hover";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*State {
|
|
|
|
name: "hover"
|
|
|
|
when: hovered && !model.selected && plasmoid.configuration.iconHoverEffect
|
|
|
|
|
|
|
|
PropertyChanges {
|
|
|
|
target: frameLoader
|
|
|
|
prefix: "hover"
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
|
|
|
|
]
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
topMargin: root.useListViewMode ? (icon.y + (icon.height / 2)) - (height / 2) : 0
|
|
|
|
}
|
|
|
|
|
|
|
|
width: implicitWidth
|
|
|
|
height: implicitHeight
|
|
|
|
}
|
|
|
|
|
|
|
|
Component.onCompleted: {
|
|
|
|
if (root.isContainment && main.GridView.view.isRootView && root.GraphicsInfo.api === GraphicsInfo.OpenGL) {
|
|
|
|
frameLoader.textShadow = textShadowComponent.createObject(frameLoader);
|
|
|
|
frameLoader.iconShadow = iconShadowComponent.createObject(frameLoader);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|