From b4f6069daa76f69268fa311b5fbbf4b793c06a6d Mon Sep 17 00:00:00 2001 From: Chris Cochrun Date: Mon, 19 Sep 2022 14:49:51 -0500 Subject: [PATCH] adding a better leftdock system based off simpler model --- src/qml/presenter/ServiceList.qml | 438 ++++++++++++++++++++++++++++++ src/resources.qrc | 1 + src/serviceitemmodel.cpp | 71 ++++- src/serviceitemmodel.h | 6 + 4 files changed, 507 insertions(+), 9 deletions(-) create mode 100644 src/qml/presenter/ServiceList.qml diff --git a/src/qml/presenter/ServiceList.qml b/src/qml/presenter/ServiceList.qml new file mode 100644 index 0000000..31a89a5 --- /dev/null +++ b/src/qml/presenter/ServiceList.qml @@ -0,0 +1,438 @@ +import QtQuick 2.13 +/* import QtQuick.Dialogs 1.0 */ +import QtQuick.Controls 2.0 as Controls +/* import QtQuick.Window 2.13 */ +import QtQuick.Layouts 1.2 +/* import QtQuick.Shapes 1.15 */ +import QtQml.Models 2.12 +/* import QtMultimedia 5.15 */ +/* import QtAudioEngine 1.15 */ +import org.kde.kirigami 2.13 as Kirigami +import "./" as Presenter +import org.presenter 1.0 + +ColumnLayout { + id: root + + property var selectedItem: serviceItemList.selected + property var hlItem + + Rectangle { + id: headerBackground + color: Kirigami.Theme.backgroundColor + height: 40 + opacity: 1.0 + Layout.fillWidth: true + + Kirigami.Heading { + id: serviceTitle + text: "Service List" + anchors.centerIn: headerBackground + padding: 5 + level: 3 + } + } + + DropArea { + id: serviceDropEnd + Layout.fillHeight: true + Layout.fillWidth: true + onDropped: (drag) => { + print("DROPPED AT END"); + appendItem(dragItemTitle, + dragItemType, + dragItemBackground, + dragItemBackgroundType, + dragItemText, + dragItemIndex); + dropHighlightLine.visible = false; + } + + keys: ["library"] + + onEntered: (drag) => { + if (drag.keys[0] === "library") { + dropHighlightLine.visible = true; + var lastItem = serviceItemList.itemAtIndex(serviceItemModel.rowCount() - 1); + dropHighlightLine.y = lastItem.y + lastItem.height; + } + } + + /* onExited: dropHighlightLine.visible = false; */ + + ListView { + id: serviceItemList + anchors.fill: parent + /* model: serviceItemModel */ + /* delegate: Kirigami.DelegateRecycler { */ + /* width: serviceItemList.width */ + /* sourceComponent: itemDelegate */ + /* } */ + clip: true + spacing: 3 + property int indexDragged + property int moveToIndex + property int draggedY + + addDisplaced: Transition { + NumberAnimation {properties: "x, y"; duration: 100} + } + moveDisplaced: Transition { + NumberAnimation { properties: "x, y"; duration: 100 } + } + remove: Transition { + NumberAnimation { properties: "x, y"; duration: 100 } + NumberAnimation { properties: "opacity"; duration: 100 } + } + + removeDisplaced: Transition { + NumberAnimation { properties: "x, y"; duration: 100 } + } + + displaced: Transition { + NumberAnimation {properties: "x, y"; duration: 100} + } + + model: serviceItemModel + + delegate: DropArea { + id: serviceDrop + implicitWidth: serviceItemList.width + height: 50 + /* enabled: false */ + + onEntered: (drag) => { + if (drag.keys[0] === "library") { + dropHighlightLine.visible = true; + dropHighlightLine.y = y - 2; + } + } + + /* onExited: dropHighlightLine.visible = false; */ + + onDropped: (drag) => { + print("DROPPED IN ITEM AREA: " + drag.keys); + print(dragItemIndex + " " + index); + const hlIndex = serviceItemList.currentIndex; + if (drag.keys[0] === "library") { + addItem(index, + dragItemTitle, + dragItemType, + dragItemBackground, + dragItemBackgroundType, + dragItemText, + dragItemIndex); + } else if (drag.keys[0] === "serviceitem") { + serviceItemModel.move(serviceItemList.indexDragged, + serviceItemList.moveToIndex); + serviceItemList.currentIndex = moveToIndex; + } + dropHighlightLine.visible = false; + } + + keys: ["library","serviceitem"] + + Kirigami.BasicListItem { + id: visServiceItem + width: serviceDrop.width + height: serviceDrop.height + anchors { + horizontalCenter: parent.horizontalCenter + verticalCenter: parent.verticalCenter + } + label: name + subtitle: type + hoverEnabled: false + supportsMouseEvents: false + backgroundColor: { + if (serviceItemList.currentIndex === index) + Kirigami.Theme.highlightColor; + else if (mouseHandler.containsMouse) + Kirigami.Theme.hoverColor; + else + Kirigami.Theme.backgroundColor; + } + textColor: { + if (serviceItemList.currentIndex === index || + mouseHandler.containsMouse) + activeTextColor; + else + Kirigami.Theme.textColor; + } + + onYChanged: serviceItemList.updateDrag(Math.round(y)); + + states: [ + State { + when: mouseHandler.drag.active + ParentChange { + target: visServiceItem + parent: serviceItemList + } + + PropertyChanges { + target: visServiceItem + backgroundColor: Kirigami.Theme.backgroundColor + textColor: Kirigami.Theme.textColor + anchors.verticalCenter: undefined + anchors.horizontalCenter: undefined + } + } + ] + + /* Drag.dragType: Drag.Automatic */ + Drag.active: mouseHandler.drag.active + Drag.hotSpot.x: width / 2 + Drag.hotSpot.y: height / 2 + Drag.keys: ["serviceitem"] + + MouseArea { + id: mouseHandler + anchors.fill: parent + hoverEnabled: true + acceptedButtons: Qt.LeftButton | Qt.RightButton + preventStealing: true + + drag { + target: visServiceItem + axis: Drag.YAxis + /* minimumY: root.y */ + /* maximumY: serviceItemList.height - serviceDrop.height */ + smoothed: false + } + + drag.onActiveChanged: { + if (mouseHandler.drag.active) { + serviceItemList.indexDragged = index; + } + } + + /* onPositionChanged: { */ + /* if (!pressed) { */ + /* return; */ + /* } */ + /* mouseArea.arrangeItem(); */ + /* } */ + + onPressed: { + serviceItemList.interactive = false; + } + + onClicked: { + if (mouse.button === Qt.RightButton) + rightClickMenu.popup(); + else { + serviceItemList.currentIndex = index; + /* currentServiceItem = index; */ + /* changeItem(index); */ + } + } + + onDoubleClicked: { + showPassiveNotification("Double Clicked") + serviceItemList.currentIndex = index; + currentServiceItem = index; + changeServiceItem(index); + } + + onReleased: { + print("should drop"); + visServiceItem.Drag.drop(); + } + } + } + + Controls.Menu { + id: rightClickMenu + x: mouseHandler.mouseX + y: mouseHandler.mouseY + 10 + Kirigami.Action { + text: "delete" + onTriggered: removeItem(index); + } + } + } + + + Kirigami.WheelHandler { + id: wheelHandler + target: serviceItemList + filterMouseEvents: true + keyNavigationEnabled: true + } + + Controls.ScrollBar.vertical: Controls.ScrollBar { + anchors.right: serviceItemList.right + anchors.rightMargin: 0 + active: hovered || pressed + } + + function updateDrag(y) { + if (moveToIndex === serviceItemList.indexAt(0,y)) + return; + else + moveToIndex = serviceItemList.indexAt(0,y); + moveRequested(indexDragged, moveToIndex); + } + + function moveRequested(oldIndex, newIndex) { + if (newIndex === oldIndex) + return; + if (newIndex === -1) + newIndex = 0; + print("moveRequested: ", oldIndex, newIndex); + serviceItemModel.move(oldIndex, newIndex); + indexDragged = newIndex; + serviceItemList.currentIndex = newIndex; + } + + } + + Rectangle { + id: dropHighlightLine + width: parent.width + height: 4 + color: Kirigami.Theme.hoverColor + visible: false + + } + Canvas { + /* asynchronous: true; */ + x: dropHighlightLine.width - 8 + y: dropHighlightLine.y - 17 + z: 1 + width: 100; height: 100; + contextType: "2d" + onPaint: { + var ctx = getContext("2d"); + ctx.fillStyle = Kirigami.Theme.hoverColor; + ctx.rotate(30); + ctx.transform(0.8, 0, 0, 0.8, 0, 30) + ctx.path = tearDropPath; + ctx.fill(); + } + visible: dropHighlightLine.visible + } + Path { + id: tearDropPath + startX: dropHighlightLine.width + startY: dropHighlightLine.y + 4 + PathSvg { + path: "M15 3 + Q16.5 6.8 25 18 + A12.8 12.8 0 1 1 5 18 + Q13.5 6.8 15 3z" + } + } + } + + Kirigami.ActionToolBar { + id: serviceToolBar + Layout.fillWidth: true + opacity: 1.0 + actions: [ + Kirigami.Action { + /* text: "Up" */ + icon.name: "arrow-up" + onTriggered: { + const oldid = serviceItemList.currentIndex; + if (oldid <= 0) + { + showPassiveNotification("wow stop trying to go nego"); + return; + } + const newid = serviceItemList.currentIndex - 1; + showPassiveNotification(oldid + " " + newid); + showPassiveNotification("Up"); + const ans = serviceItemModel.move(oldid, newid); + if (ans) + { + serviceItemList.currentIndex = newid; + showPassiveNotification("move was successful, newid: " + + serviceItemList.currentIndex); + } + else + showPassiveNotification("move was unsuccessful") + } + }, + Kirigami.Action { + /* text: "Down" */ + icon.name: "arrow-down" + onTriggered: { + const oldid = serviceItemList.currentIndex; + if (oldid + 1 >= serviceItemList.count) + { + showPassiveNotification("wow you dummy you can't got further down"); + return; + }; + const newid = findId(serviceItemList.currentIndex + 2); + showPassiveNotification(oldid + " " + newid); + showPassiveNotification("Down"); + const ans = serviceItemModel.move(oldid, newid); + if (ans) + { + serviceItemList.currentIndex = newid - 1; + showPassiveNotification("move was successful, newid: " + + serviceItemList.currentIndex); + } + else + showPassiveNotification("move was unsuccessful, newid: " + + newid); + + function findId(id) { + if (id >= serviceItemList.count) + return serviceItemList.count; + else + return id; + } + } + }, + Kirigami.Action { + /* text: "Remove" */ + icon.name: "delete" + onTriggered: { + showPassiveNotification("remove"); + removeItem(serviceItemList.currentIndex); + } + } + ] + } + + Component.onCompleted: { + totalServiceItems = serviceItemList.count; + print("THE TOTAL SERVICE ITEMS: " + totalServiceItems); + } + + function removeItem(index) { + serviceItemModel.removeItem(index); + totalServiceItems--; + } + + function addItem(index, name, type, + background, backgroundType, text, itemID) { + const newtext = songsqlmodel.getLyricList(itemID); + print("adding: " + name + " of type " + type); + serviceItemModel.insertItem(index, name, + type, background, + backgroundType, newtext); + totalServiceItems++; + } + + function appendItem(name, type, background, backgroundType, text, itemID) { + print("adding: " + name + " of type " + type); + let lyrics; + if (type === "song") { + print(itemID); + lyrics = songsqlmodel.getLyricList(itemID); + print(lyrics); + } + + print(background); + print(backgroundType); + + serviceItemModel.addItem(name, type, background, + backgroundType, lyrics); + totalServiceItems++; + } + +} diff --git a/src/resources.qrc b/src/resources.qrc index f7ef11d..7866e05 100644 --- a/src/resources.qrc +++ b/src/resources.qrc @@ -3,6 +3,7 @@ qml/main.qml qml/presenter/qmldir qml/presenter/LeftDock.qml + qml/presenter/ServiceList.qml qml/presenter/MainWindow.qml qml/presenter/Library.qml qml/presenter/Header.qml diff --git a/src/serviceitemmodel.cpp b/src/serviceitemmodel.cpp index fe326b1..f97b83c 100644 --- a/src/serviceitemmodel.cpp +++ b/src/serviceitemmodel.cpp @@ -8,7 +8,7 @@ ServiceItemModel::ServiceItemModel(QObject *parent) : QAbstractListModel(parent) { - addItem(new ServiceItem("10,000 Resons", "song", + addItem(new ServiceItem("10,000 Reasons", "song", "file:/home/chris/nextcloud/tfc/openlp/CMG - Nature King 21.jpg", "image", QStringList("Yip Yip"))); addItem(new ServiceItem("Marvelous Light", "song", @@ -114,6 +114,23 @@ Qt::ItemFlags ServiceItemModel::flags(const QModelIndex &index) const { return Qt::ItemIsEditable; // FIXME: Implement me! } +// int ServiceItemModel::index(int row, int column, const QModelIndex &parent) { +// if (!hasIndex(row, column, parent)) +// return QModelIndex(); + +// ServiceItem *parentItem; + +// if (!parent.isValid()) +// parentItem = rootItem; +// else +// parentItem = static_cast(parent.internalPointer()); + +// ServiceItem *childItem = parentItem->child(row); +// if (childItem) +// return createIndex(row, column, childItem); +// return QModelIndex(); +// } + void ServiceItemModel::addItem(ServiceItem *item) { const int index = m_items.size(); qDebug() << index; @@ -181,23 +198,59 @@ void ServiceItemModel::removeItem(int index) { bool ServiceItemModel::move(int sourceIndex, int destIndex) { qDebug() << index(sourceIndex).row(); qDebug() << index(destIndex).row(); - // beginResetModel(); QModelIndex parent = index(sourceIndex).parent(); if (sourceIndex >= 0 && sourceIndex != destIndex && - destIndex >= -1 && destIndex < rowCount() && + destIndex >= -1 && destIndex <= rowCount() && sourceIndex < rowCount()) { qDebug() << "starting move: " << "source: " << sourceIndex << "dest: " << destIndex; - bool begsuc = beginMoveRows(QModelIndex(), sourceIndex, - sourceIndex, QModelIndex(), destIndex); + bool begsuc = beginMoveRows(parent, sourceIndex, + sourceIndex, parent, destIndex); if (begsuc) { - if (destIndex = -1) - m_items.move(sourceIndex, 0); + if (destIndex == -1) + { + qDebug() << "dest was too small, moving to row 0"; + m_items.move(sourceIndex, 0); + } else - m_items.move(sourceIndex, destIndex); + { + qDebug() << "dest was not too small"; + if (destIndex >= m_items.size()) + { + qDebug() << "destIndex too big, moving to end"; + m_items.move(sourceIndex, m_items.size() - 1); + } + else + m_items.move(sourceIndex, destIndex); + } endMoveRows(); + return true; } + qDebug() << "Can't move row, not sure why, sourceIndex: " + << sourceIndex << " destIndex: " << destIndex; + return false; } - return true; + qDebug() << "Can't move row, invalid options, sourceIndex: " + << sourceIndex << " destIndex: " << destIndex; + return false; +} + +bool ServiceItemModel::move(int sourceIndex, int destIndex, bool simple) { + qDebug() << index(sourceIndex).row(); + qDebug() << index(destIndex).row(); + QModelIndex parent = index(sourceIndex).parent(); + + if (simple) + { + if (moveRow(parent, sourceIndex, parent, destIndex)) + return true; + else + { + qDebug() << "not sure..."; + return false; + } + } + + return false; } QVariantMap ServiceItemModel::getItem(int index) const { diff --git a/src/serviceitemmodel.h b/src/serviceitemmodel.h index 4536b2c..1a76624 100644 --- a/src/serviceitemmodel.h +++ b/src/serviceitemmodel.h @@ -24,10 +24,15 @@ public: // Basic functionality: int rowCount(const QModelIndex &parent = QModelIndex()) const override; + // int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QHash roleNames() const override; + // Q_INVOKABLE int index(int row, int column, + // const QModelIndex &parent = QModelIndex()) const override; + // Q_INVOKABLE QModelIndex parent(const QModelIndex &index) const override; + // Editable: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; @@ -56,6 +61,7 @@ public: const QString &backgroundType, const QStringList &text); Q_INVOKABLE void removeItem(int index); Q_INVOKABLE bool move(int sourceIndex, int destIndex); + Q_INVOKABLE bool move(int sourceIndex, int destIndex, bool simple); Q_INVOKABLE QVariantMap getItem(int index) const; private: