1/*
2    SPDX-FileCopyrightText: 2011 Marco Martin <mart@kde.org>
3    SPDX-FileCopyrightText: 2015 Kai Uwe Broulik <kde@privat.broulik.de>
4    SPDX-FileCopyrightText: 2021 Michail Vourlakos <mvourlakos@gmail.com>
5
6    SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9import QtQuick 2.4
10import QtQuick.Layouts 1.1
11
12import org.kde.plasma.components 2.0 as PlasmaComponents
13import org.kde.plasma.extras 2.0 as PlasmaExtras
14import org.kde.plasma.core 2.0 as PlasmaCore
15import org.kde.draganddrop 2.0
16
17Item {
18    id: delegate
19
20    readonly property string pluginName: model.pluginName
21    readonly property bool pendingUninstall: pendingUninstallTimer.applets.indexOf(pluginName) > -1
22
23    width: list.cellWidth
24    height: list.cellHeight
25
26    DragArea {
27        anchors.fill: parent
28        supportedActions: Qt.MoveAction | Qt.LinkAction
29        //onDragStarted: tooltipDialog.visible = false
30        delegateImage: decoration
31        enabled: !delegate.pendingUninstall
32        mimeData {
33            source: parent
34        }
35        Component.onCompleted: mimeData.setData("text/x-plasmoidservicename", pluginName)
36
37        onDragStarted: {
38            kwindowsystem.showingDesktop = true;
39            main.draggingWidget = true;
40        }
41        onDrop: {
42            main.draggingWidget = false;
43        }
44
45        MouseArea {
46            id: mouseArea
47            anchors.fill: parent
48            hoverEnabled: true
49            onDoubleClicked: {
50                if (!delegate.pendingUninstall) {
51                    widgetExplorer.addApplet(pluginName)
52                }
53            }
54            onEntered: delegate.GridView.view.currentIndex = index
55            onExited: delegate.GridView.view.currentIndex = - 1
56        }
57
58        ColumnLayout {
59            id: mainLayout
60            spacing: units.smallSpacing
61            anchors {
62                left: parent.left
63                right: parent.right
64                //bottom: parent.bottom
65                margins: units.smallSpacing * 2
66                rightMargin: units.smallSpacing * 2 // don't cram the text to the border too much
67                top: parent.top
68            }
69
70            Item {
71                id: iconContainer
72                width: units.iconSizes.enormous
73                height: width
74                Layout.alignment: Qt.AlignHCenter
75                opacity: delegate.pendingUninstall ? 0.6 : 1
76                Behavior on opacity {
77                    OpacityAnimator {
78                        duration: units.longDuration
79                        easing.type: Easing.InOutQuad
80                    }
81                }
82
83                Item {
84                    id: iconWidget
85                    anchors.fill: parent
86                    PlasmaCore.IconItem {
87                        anchors.fill: parent
88                        source: model.decoration
89                        visible: model.screenshot === ""
90                    }
91                    Image {
92                        width: units.iconSizes.enormous
93                        height: width
94                        anchors.fill: parent
95                        fillMode: Image.PreserveAspectFit
96                        source: model.screenshot
97                    }
98                }
99
100                Item {
101                    id: badgeMask
102                    anchors.fill: parent
103
104                    Rectangle {
105                        x: Math.round(-units.smallSpacing * 1.5 / 2)
106                        y: x
107                        width: runningBadge.width + Math.round(units.smallSpacing * 1.5)
108                        height: width
109                        radius: height
110                        visible: running && delegate.GridView.isCurrentItem
111                    }
112                }
113
114                Rectangle {
115                    id: runningBadge
116                    width: height
117                    height: Math.round(theme.mSize(countLabel.font).height * 1.3)
118                    radius: height
119                    color: theme.highlightColor
120                    visible: running && delegate.GridView.isCurrentItem
121                    onVisibleChanged: maskShaderSource.scheduleUpdate()
122
123                    PlasmaComponents.Label {
124                        id: countLabel
125                        anchors.fill: parent
126                        horizontalAlignment: Text.AlignHCenter
127                        verticalAlignment: Text.AlignVCenter
128                        text: running
129                    }
130                }
131
132                ShaderEffect {
133                    anchors.fill: parent
134                    property var source: ShaderEffectSource {
135                        sourceItem: iconWidget
136                        hideSource: true
137                        live: false
138                    }
139                    property var mask: ShaderEffectSource {
140                        id: maskShaderSource
141                        sourceItem: badgeMask
142                        hideSource: true
143                        live: false
144                    }
145
146                    supportsAtlasTextures: true
147
148                    fragmentShader: "
149                        varying highp vec2 qt_TexCoord0;
150                        uniform highp float qt_Opacity;
151                        uniform lowp sampler2D source;
152                        uniform lowp sampler2D mask;
153                        void main() {
154                            gl_FragColor = texture2D(source, qt_TexCoord0.st) * (1.0 - (texture2D(mask, qt_TexCoord0.st).a)) * qt_Opacity;
155                        }
156                    "
157                }
158
159                PlasmaComponents.ToolButton {
160                    id: uninstallButton
161                    anchors {
162                        top: parent.top
163                        right: parent.right
164                    }
165                    iconSource: delegate.pendingUninstall ? "edit-undo" : "edit-delete"
166                    // we don't really "undo" anything but we'll pretend to the user that we do
167                    tooltip: delegate.pendingUninstall ? i18nd("plasma_shell_org.kde.plasma.desktop", "Undo uninstall")
168                                                       : i18nd("plasma_shell_org.kde.plasma.desktop", "Uninstall widget")
169                    flat: false
170                    visible: model.local && delegate.GridView.isCurrentItem
171
172                    onHoveredChanged: {
173                        if (hovered) {
174                            // hovering the uninstall button triggers onExited of the main mousearea
175                            delegate.GridView.view.currentIndex = index
176                        }
177                    }
178
179                    onClicked: {
180                        var pending = pendingUninstallTimer.applets
181                        if (delegate.pendingUninstall) {
182                            var index = pending.indexOf(pluginName)
183                            if (index > -1) {
184                                pending.splice(index, 1)
185                            }
186                        } else {
187                            pending.push(pluginName)
188                        }
189                        pendingUninstallTimer.applets = pending
190
191                        if (pending.length) {
192                            pendingUninstallTimer.restart()
193                        } else {
194                            pendingUninstallTimer.stop()
195                        }
196                    }
197                }
198            }
199            PlasmaExtras.Heading {
200                id: heading
201                Layout.fillWidth: true
202                level: 4
203                text: model.name
204                elide: Text.ElideRight
205                wrapMode: Text.WordWrap
206                maximumLineCount: 2
207                lineHeight: 0.95
208                horizontalAlignment: Text.AlignHCenter
209            }
210            PlasmaComponents.Label {
211                Layout.fillWidth: true
212                // otherwise causes binding loop due to the way the Plasma sets the height
213                height: implicitHeight
214                text: model.description
215                font: theme.smallestFont
216                wrapMode: Text.WordWrap
217                elide: Text.ElideRight
218                maximumLineCount: heading.lineCount === 1 ? 3 : 2
219                horizontalAlignment: Text.AlignHCenter
220            }
221        }
222    }
223}
224