1//============================================================================= 2// MuseScore 3// Music Composition & Notation 4// 5// Copyright (C) 2019 Werner Schweer and others 6// 7// This program is free software; you can redistribute it and/or modify 8// it under the terms of the GNU General Public License version 2. 9// 10// This program is distributed in the hope that it will be useful, 11// but WITHOUT ANY WARRANTY; without even the implied warranty of 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13// GNU General Public License for more details. 14// 15// You should have received a copy of the GNU General Public License 16// along with this program; if not, write to the Free Software 17// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 18//============================================================================= 19 20import QtQuick 2.8 21import QtQuick.Controls 2.1 22import QtQml.Models 2.2 23import MuseScore.Palette 3.3 24 25import "utils.js" as Utils 26 27StyledPopup { 28 id: moreElementsPopup 29 30 property var poolPalette : null 31 property var poolPaletteRootIndex: null 32 property PaletteController poolPaletteController: null 33 34 property var customPalette : null 35 property var customPaletteRootIndex: null 36 property PaletteController customPaletteController: null 37 38 property PaletteElementEditor elementEditor: customPaletteRootIndex && customPaletteController ? customPaletteController.elementEditor(customPaletteRootIndex) : null 39 40 property string paletteName 41 readonly property string libraryPaletteName: (poolPalette && poolPaletteRootIndex) ? poolPalette.data(poolPaletteRootIndex, Qt.DisplayRole) : "" 42 property bool paletteIsCustom: false 43 property bool paletteEditingEnabled: true 44 45 property size cellSize 46 property bool drawGrid 47 48 property int maxHeight: 400 49 implicitHeight: column.height + topPadding + bottomPadding 50 51 property bool enablePaletteAnimations: false // disabled by default to avoid unnecessary "add" animations on opening this popup at first time 52 53 signal addElementsRequested(var mimeDataList) 54 55 Column { 56 id: column 57 width: parent.width 58 spacing: 8 59 60 StyledButton { 61 id: addToPaletteButton 62 width: parent.width 63 64 text: qsTr("Add to %1").arg(paletteName) 65 enabled: moreElementsPopup.paletteEditingEnabled && (masterPaletteSelectionModel.hasSelection || customPaletteSelectionModel.hasSelection) 66 67 onClicked: { 68 function collectMimeData(palette, selection) { 69 const selectedList = selection.selectedIndexes; 70 var mimeArr = []; 71 for (var i = 0; i < selectedList.length; i++) { 72 const mimeData = palette.paletteModel.data(selectedList[i], PaletteTreeModel.MimeDataRole); 73 mimeArr.push(mimeData); 74 } 75 return mimeArr; 76 } 77 78 const mimeMasterPalette = collectMimeData(masterPalette, masterPaletteSelectionModel); 79 const mimeCustomPalette = collectMimeData(customPalette, customPaletteSelectionModel); 80 81 masterPaletteSelectionModel.clear(); 82 customPaletteSelectionModel.clear(); 83 84 if (mimeMasterPalette.length) 85 addElementsRequested(mimeMasterPalette); 86 if (mimeCustomPalette.length) 87 addElementsRequested(mimeCustomPalette); 88 } 89 } 90 91 Item { 92 id: masterIndexControls 93 enabled: moreElementsPopup.paletteIsCustom && poolPalette && poolPaletteRootIndex 94 visible: enabled 95 anchors { left: parent.left; right: parent.right } 96 implicitHeight: prevButton.implicitHeight 97 StyledButton { 98 id: prevButton 99 width: height 100 anchors.left: parent.left 101 flat: true 102 text: "<" // TODO: replace? 103 104 property var prevIndex: { 105 if (!masterIndexControls.enabled) 106 return null; 107 108 var idx = poolPalette.sibling(poolPaletteRootIndex.row - 1, 0, poolPaletteRootIndex); 109 if (!idx.valid) { 110 const nrows = poolPalette.rowCount(poolPaletteRootIndex.parent); 111 idx = poolPalette.sibling(nrows - 1, 0, poolPaletteRootIndex) 112 } 113 return idx; 114 } 115 116 enabled: prevIndex && prevIndex.valid 117 118 onClicked: poolPaletteRootIndex = prevIndex; 119 } 120 Text { 121 anchors.centerIn: parent 122 text: moreElementsPopup.libraryPaletteName 123 font: globalStyle.font 124 color: globalStyle.windowText 125 } 126 StyledButton { 127 width: height 128 anchors.right: parent.right 129 flat: true 130 text: ">" // TODO: replace? 131 132 property var nextIndex: { 133 if (!masterIndexControls.enabled) 134 return null; 135 136 var idx = poolPalette.sibling(poolPaletteRootIndex.row + 1, 0, poolPaletteRootIndex); 137 if (!idx.valid) 138 idx = poolPalette.sibling(0, 0, poolPaletteRootIndex) 139 return idx; 140 } 141 142 enabled: nextIndex && nextIndex.valid 143 144 onClicked: poolPaletteRootIndex = nextIndex 145 } 146 } 147 148 Rectangle { 149 id: paletteContainer 150 width: parent.width 151 height: childrenRect.height 152 border { width: 1; color: "black" } 153 color: mscore.paletteBackground 154 155 readonly property int availableHeight: moreElementsPopup.maxHeight - addToPaletteButton.height - (masterIndexControls ? masterIndexControls.height : 0) - bottomText.height - (elementEditorButton.visible ? elementEditorButton.height : 0) - 40 156 157 Column { 158 width: parent.width 159 padding: 8 160 property real contentWidth: width - 2 * padding 161 162 ItemSelectionModel { 163 id: masterPaletteSelectionModel 164 model: masterPalette.paletteModel 165 } 166 167 Palette { 168 id: masterPalette 169 height: Math.max( 170 cellSize.height, 171 Math.min( 172 implicitHeight, 173 paletteContainer.availableHeight - (customPalette.visible ? (customPalette.height + customPaletteLabel.height) : 0) 174 ) 175 ) 176 width: parent.contentWidth 177 178 ScrollBar.vertical: ScrollBar { enabled: masterPalette.height < masterPalette.implicitHeight } 179 180 // TODO: change settings to "hidden" model? 181 cellSize: moreElementsPopup.cellSize 182 drawGrid: moreElementsPopup.drawGrid 183 184 paletteModel: moreElementsPopup.poolPalette 185 paletteRootIndex: moreElementsPopup.poolPaletteRootIndex 186 paletteController: moreElementsPopup.poolPaletteController 187 selectionModel: masterPaletteSelectionModel 188 189 enableAnimations: moreElementsPopup.enablePaletteAnimations 190 } 191 192 ToolSeparator { 193 id: separator 194 visible: !customPalette.empty 195 orientation: Qt.Horizontal 196 width: parent.contentWidth 197 } 198 199 Item { 200 width: separator.width 201 implicitHeight: deleteButton.implicitHeight 202 visible: !customPalette.empty 203 204 Text { 205 id: customPaletteLabel 206 height: deleteButton.height 207 verticalAlignment: Text.AlignVCenter 208 text: qsTr("Custom") 209 } 210 211 StyledToolButton { 212 id: deleteButton 213 width: height 214 anchors.right: parent.right 215 text: qsTr("Delete element(s)") 216 enabled: customPaletteSelectionModel.hasSelection 217 218 ToolTip.text: text 219 220 onHoveredChanged: { 221 if (hovered) { 222 mscore.tooltip.item = deleteButton; 223 mscore.tooltip.text = deleteButton.text; 224 } else if (mscore.tooltip.item == deleteButton) 225 mscore.tooltip.item = null; 226 } 227 228 padding: 4 229 230 contentItem: StyledIcon { 231 source: "icons/TrashCan.svg" 232 color: "black" 233 opacity: deleteButton.enabled ? 1.0 : 0.1 234 } 235 236 onClicked: Utils.removeSelectedItems(moreElementsPopup.customPaletteController, customPaletteSelectionModel, moreElementsPopup.customPaletteRootIndex); 237 } 238 } 239 240 ItemSelectionModel { 241 id: customPaletteSelectionModel 242 model: customPalette.paletteModel 243 } 244 245 Palette { 246 id: customPalette 247 visible: !empty 248 width: parent.contentWidth 249 250 cellSize: control.cellSize 251 drawGrid: control.drawGrid 252 253 paletteModel: moreElementsPopup.customPalette 254 paletteRootIndex: moreElementsPopup.customPaletteRootIndex 255 paletteController: moreElementsPopup.customPaletteController 256 selectionModel: customPaletteSelectionModel 257 258 enableAnimations: moreElementsPopup.enablePaletteAnimations 259 } 260 } 261 } 262 263 Item { 264 // spacer item, adds extra spacing before "drag items..." text 265 width: 1 266 height: 2 - column.spacing 267 } 268 269 Text { 270 id: bottomText 271 width: parent.width 272 text: qsTr("Drag items to the palette or directly on your score") 273 color: globalStyle.windowText 274 horizontalAlignment: Text.AlignHCenter 275 wrapMode: Text.WordWrap 276 font.family: globalStyle.font.family 277 // make this label's font slightly smaller than other popup text 278 font.pointSize: globalStyle.font.pointSize * 0.8 279 } 280 281 Item { 282 // spacer item, adds extra spacing after "drag items..." text 283 width: 1 284 height: 2 - column.spacing 285 } 286 287 StyledButton { 288 id: elementEditorButton 289 visible: moreElementsPopup.elementEditor && moreElementsPopup.elementEditor.valid 290 enabled: moreElementsPopup.paletteEditingEnabled 291 width: parent.width 292 text: moreElementsPopup.elementEditor ? moreElementsPopup.elementEditor.actionName : "" 293 onClicked: moreElementsPopup.elementEditor.open() 294 } 295 } 296} 297