diff --git a/src/gui/GraphEditorWidget.cpp b/src/gui/GraphEditorWidget.cpp index 0f16191..86e0bdf 100644 --- a/src/gui/GraphEditorWidget.cpp +++ b/src/gui/GraphEditorWidget.cpp @@ -74,6 +74,115 @@ private: NodeVolumeState m_next{}; }; +class DeleteVirtualNodeCommand : public QUndoCommand +{ +public: + struct VirtualNodeData { + QString name; + QString description; + Potato::MediaClass mediaClass; + int channels; + int rate; + QPointF position; + NodeVolumeState volumeState; + }; + + DeleteVirtualNodeCommand(GraphEditorWidget *widget, + QtNodes::BasicGraphicsScene *scene, + const QList &nodeIds) + : m_widget(widget) + , m_scene(scene) + { + if (!widget || !scene) { + return; + } + + PipeWireGraphModel *model = widget->m_model; + if (!model) { + return; + } + + for (const auto nodeId : nodeIds) { + const Potato::NodeInfo *info = model->nodeInfo(nodeId); + if (!info || info->type != Potato::NodeType::Virtual) { + continue; + } + + VirtualNodeData data; + data.name = info->name; + data.description = info->description; + data.mediaClass = info->mediaClass; + const int inPortSize = static_cast(info->inputPorts.size()); + const int outPortSize = static_cast(info->outputPorts.size()); + data.channels = (inPortSize > outPortSize) ? inPortSize : outPortSize; + if (data.channels == 0) { + data.channels = 2; + } + data.rate = 48000; + data.position = model->nodeData(nodeId, QtNodes::NodeRole::Position).toPointF(); + + NodeVolumeState volumeState; + if (model->nodeVolumeState(info->id, volumeState)) { + data.volumeState = volumeState; + } + + m_virtualNodes.append(data); + m_nodeIds.append(nodeId); + } + + setText(QString("Delete Virtual Node")); + } + + void undo() override + { + if (!m_widget || m_virtualNodes.isEmpty()) { + return; + } + + auto *controller = m_widget->m_controller; + auto *model = m_widget->m_model; + if (!controller || !model) { + return; + } + + for (const auto &data : m_virtualNodes) { + bool success = false; + if (data.mediaClass == Potato::MediaClass::AudioSource) { + success = controller->createVirtualSource(data.name, data.description, data.channels, data.rate); + } else { + success = controller->createVirtualSink(data.name, data.description, data.channels, data.rate); + } + + if (success) { + m_widget->m_pendingPastePositions.insert(data.name, data.position); + m_widget->m_pendingPasteVolumes.insert(data.name, data.volumeState); + } + } + } + + void redo() override + { + if (!m_widget) { + return; + } + + PipeWireGraphModel *model = m_widget->m_model; + if (!model) { + return; + } + + for (const auto nodeId : m_nodeIds) { + model->deleteNode(nodeId); + } + } + +private: + GraphEditorWidget *m_widget = nullptr; + QtNodes::BasicGraphicsScene *m_scene = nullptr; + QList m_virtualNodes; + QList m_nodeIds; +}; + GraphEditorWidget::GraphEditorWidget(Potato::PipeWireController *controller, QWidget *parent) : QWidget(parent) , m_controller(controller) @@ -1369,7 +1478,40 @@ void GraphEditorWidget::duplicateSelection() void GraphEditorWidget::deleteSelection() { - if (m_scene) { + if (!m_scene) { + return; + } + + const QList items = m_scene->selectedItems(); + QList virtualNodeIds; + QList otherNodeIds; + + for (auto *item : items) { + if (auto *nodeObj = qgraphicsitem_cast(item)) { + const Potato::NodeInfo *info = m_model->nodeInfo(nodeObj->nodeId()); + if (info && info->type == Potato::NodeType::Virtual) { + virtualNodeIds.append(nodeObj->nodeId()); + } else if (info) { + otherNodeIds.append(nodeObj->nodeId()); + } + } + } + + if (!virtualNodeIds.isEmpty()) { + m_scene->undoStack().push(new DeleteVirtualNodeCommand(this, m_scene, virtualNodeIds)); + } + + if (!otherNodeIds.isEmpty()) { + m_scene->clearSelection(); + for (const auto nodeId : otherNodeIds) { + if (const auto *nodeObj = m_scene->nodeGraphicsObject(nodeId)) { + const_cast(nodeObj)->setSelected(true); + } + } + m_scene->undoStack().push(new QtNodes::DeleteCommand(m_scene)); + } + + if (virtualNodeIds.isEmpty() && otherNodeIds.isEmpty() && !items.isEmpty()) { m_scene->undoStack().push(new QtNodes::DeleteCommand(m_scene)); } } diff --git a/src/gui/GraphEditorWidget.h b/src/gui/GraphEditorWidget.h index 6c1e70e..2580504 100644 --- a/src/gui/GraphEditorWidget.h +++ b/src/gui/GraphEditorWidget.h @@ -27,12 +27,14 @@ class QSplitter; class QTabWidget; class PresetManager; class VolumeChangeCommand; +class DeleteVirtualNodeCommand; class GraphEditorWidget : public QWidget { Q_OBJECT friend class VolumeChangeCommand; + friend class DeleteVirtualNodeCommand; public: explicit GraphEditorWidget(Potato::PipeWireController *controller, QWidget *parent = nullptr);