1/* 2 * Copyright (C) 2013, 2014, 2015, 2016, 2017 3 * Jean-Luc Barriere <jlbarriere68@gmail.com> 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; version 3. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program. If not, see <http://www.gnu.org/licenses/>. 16 */ 17 18import QtQuick 2.9 19import QtQuick.Controls 2.2 20import "ListItemActions" 21 22Row { 23 id: row 24 anchors.leftMargin: units.gu(1) 25 anchors.rightMargin: units.gu(2) 26 27 property real contentHeight: units.gu(6) 28 property alias column: columnComponent.sourceComponent 29 property real coverSize: contentHeight 30 property string noCover: "qrc:/images/no_cover.png" 31 property var imageSources: [] 32 property string imageSource: "" 33 property string description: "" 34 property string rowNumber: "" 35 property string rowNumberColor: styleMusic.view.primaryColor 36 property bool isFavorite: false 37 property alias checked: select.checked 38 property alias checkable: select.checkable 39 40 property bool menuVisible: false 41 property alias menuItems: optionsMenu.contentData 42 property alias actionVisible: action.visible 43 property alias actionIconSource: action.iconSource 44 property alias action2Visible: action2.visible 45 property alias action2IconSource: action2.iconSource 46 property alias action3Visible: action3.visible 47 property alias action3IconSource: action3.iconSource 48 49 signal actionPressed 50 signal action2Pressed 51 signal action3Pressed 52 signal selected 53 signal deselected 54 55 signal imageError(var index) 56 57 spacing: units.gu(1) 58 59 state: "default" 60 states: [ 61 State { 62 name: "default" 63 PropertyChanges { target: select; anchors.rightMargin: -select.width; opacity: anchors.rightMargin > -select.width ? 1 : 0; } 64 PropertyChanges { target: menu; anchors.rightMargin: 0; opacity: 1 } 65 //PropertyChanges { target: action; visible: actionIconSource !== "" } 66 }, 67 State { 68 name: "selection" 69 PropertyChanges { target: select; anchors.rightMargin: 0 } 70 PropertyChanges { target: menu; anchors.rightMargin: -select.width; opacity: anchors.rightMargin > -select.width ? 1 : 0; } 71 //PropertyChanges { target: action; visible: false } 72 } 73 ] 74 75 Item { 76 height: contentHeight 77 width: image.width 78 79 Rectangle { 80 id: image 81 height: coverSize 82 width: cover.visible ? height : rowNumber.visible ? units.gu(5) : units.dp(1) 83 border.color: cover.visible ? "grey" : "transparent" 84 color: "transparent" 85 anchors.verticalCenter: parent.verticalCenter 86 87 Text { 88 id: rowNumber 89 anchors.verticalCenter: parent.verticalCenter 90 anchors.left: parent.left 91 anchors.right: parent.right 92 horizontalAlignment: Text.AlignHCenter 93 verticalAlignment: Text.AlignVCenter 94 elide: Text.ElideLeft 95 text: row.rowNumber 96 color: row.rowNumberColor 97 font.pointSize: text.length < 3 ? units.fs("x-large") : units.fs("small") 98 visible: text !== "" 99 } 100 101 Image { 102 id: cover 103 anchors { 104 verticalCenter: parent.verticalCenter 105 } 106 property int index: 0 107 asynchronous: true 108 fillMode: Image.PreserveAspectCrop 109 height: coverSize 110 width: height 111 source: imageSources.length ? imageSources[index].art : noCover 112 sourceSize.height: 512 113 sourceSize.width: 512 114 115 onStatusChanged: { 116 if (status === Image.Error) { 117 row.imageError(index) 118 if (imageSources.length > (index + 1)) { 119 source = imageSources[++index].art 120 } else { 121 source = noCover 122 } 123 } else if (status === Image.Ready) { 124 imageSource = source; 125 } 126 } 127 visible: imageSources.length > 0 128 } 129 } 130 } 131 132 Loader { 133 id: columnComponent 134 anchors { 135 verticalCenter: parent.verticalCenter 136 } 137 138 width: parent.width - image.width - parent.spacing - menu.width - action.width - action2.width - action3.width - units.gu(1) 139 140 onSourceComponentChanged: { 141 for (var i=0; i < item.children.length; i++) { 142 if (item.children[i].text !== undefined) { 143 item.children[i].elide = Text.ElideRight 144 item.children[i].maximumLineCount = 1 145 item.children[i].wrapMode = Text.NoWrap 146 item.children[i].verticalAlignment = Text.AlignVCenter 147 } 148 // binds to width so it is updated when screen size changes 149 item.children[i].width = Qt.binding(function () { return width; }) 150 } 151 } 152 } 153 154 Item { 155 id: action3 156 visible: false 157 anchors.right: action2.left 158 anchors.rightMargin: units.gu(1) 159 width: visible ? units.gu(5) : 0 160 property alias iconSource: icon3.source 161 162 Rectangle { 163 color: "transparent" 164 width: parent.width 165 height: row.height 166 167 Icon { 168 id: icon3 169 source: "" 170 width: parent.width 171 height: width 172 anchors.centerIn: parent 173 onClicked: action3Pressed() 174 } 175 } 176 } 177 178 Item { 179 id: action2 180 visible: false 181 anchors.right: action.left 182 anchors.rightMargin: units.gu(1) 183 width: visible ? units.gu(5) : 0 184 property alias iconSource: icon2.source 185 186 Rectangle { 187 color: "transparent" 188 width: parent.width 189 height: row.height 190 191 Icon { 192 id: icon2 193 source: "" 194 width: parent.width 195 height: width 196 anchors.centerIn: parent 197 onClicked: action2Pressed() 198 } 199 } 200 } 201 202 Item { 203 id: action 204 visible: false 205 anchors.right: menu.left 206 anchors.rightMargin: units.gu(1) 207 width: units.gu(5) 208 property string iconSource: "" 209 210 Rectangle { 211 color: "transparent" 212 width: parent.width 213 height: row.height 214 215 Icon { 216 id: icon 217 source: isFavorite ? "qrc:/images/starred.svg" : action.iconSource 218 width: parent.width 219 height: width 220 anchors.centerIn: parent 221 onClicked: actionPressed() 222 } 223 } 224 } 225 226 Item { 227 id: menu 228 anchors.right: select.left 229 width: visible ? units.gu(5) : 0 230 visible: menuVisible 231 232 Rectangle { 233 color: "transparent" 234 width: parent.width 235 height: row.height 236 237 Icon { 238 width: menu.visible ? units.gu(5) : 0 239 height: width 240 anchors.centerIn: parent 241 source: "qrc:/images/contextual-menu.svg" 242 243 onClicked: optionsMenu.open() 244 245 Menu { 246 id: optionsMenu 247 width: implicitWidth * units.scaleFactor 248 x: parent.width - width 249 transformOrigin: Menu.TopRight 250 } 251 } 252 } 253 254 Behavior on anchors.rightMargin { 255 NumberAnimation { duration: 50 } 256 } 257 } 258 259 Item { 260 id: select 261 anchors.right: parent.right 262 width: units.gu(6) 263 visible: true 264 property alias checked: control.checked 265 property alias checkable: control.checkable 266 267 Rectangle { 268 color: "transparent" 269 width: control.width 270 height: row.height 271 272 MusicCheckBox { 273 id: control 274 anchors.centerIn: parent 275 276 onClicked: { 277 if (checked) { 278 selected(); 279 } else { 280 deselected(); 281 } 282 } 283 } 284 } 285 286 Behavior on anchors.rightMargin { 287 NumberAnimation { duration: 50 } 288 } 289 } 290 291} 292