Undo deletion

This commit is contained in:
Joey Yakimowich-Payne 2026-01-28 11:58:18 -07:00
commit 453003cb25
2 changed files with 145 additions and 1 deletions

View file

@ -74,6 +74,115 @@ private:
NodeVolumeState m_next{}; 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<QtNodes::NodeId> &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<int>(info->inputPorts.size());
const int outPortSize = static_cast<int>(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<VirtualNodeData> m_virtualNodes;
QList<QtNodes::NodeId> m_nodeIds;
};
GraphEditorWidget::GraphEditorWidget(Potato::PipeWireController *controller, QWidget *parent) GraphEditorWidget::GraphEditorWidget(Potato::PipeWireController *controller, QWidget *parent)
: QWidget(parent) : QWidget(parent)
, m_controller(controller) , m_controller(controller)
@ -1369,7 +1478,40 @@ void GraphEditorWidget::duplicateSelection()
void GraphEditorWidget::deleteSelection() void GraphEditorWidget::deleteSelection()
{ {
if (m_scene) { if (!m_scene) {
return;
}
const QList<QGraphicsItem*> items = m_scene->selectedItems();
QList<QtNodes::NodeId> virtualNodeIds;
QList<QtNodes::NodeId> otherNodeIds;
for (auto *item : items) {
if (auto *nodeObj = qgraphicsitem_cast<QtNodes::NodeGraphicsObject*>(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<QtNodes::NodeGraphicsObject*>(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)); m_scene->undoStack().push(new QtNodes::DeleteCommand(m_scene));
} }
} }

View file

@ -27,12 +27,14 @@ class QSplitter;
class QTabWidget; class QTabWidget;
class PresetManager; class PresetManager;
class VolumeChangeCommand; class VolumeChangeCommand;
class DeleteVirtualNodeCommand;
class GraphEditorWidget : public QWidget class GraphEditorWidget : public QWidget
{ {
Q_OBJECT Q_OBJECT
friend class VolumeChangeCommand; friend class VolumeChangeCommand;
friend class DeleteVirtualNodeCommand;
public: public:
explicit GraphEditorWidget(Potato::PipeWireController *controller, QWidget *parent = nullptr); explicit GraphEditorWidget(Potato::PipeWireController *controller, QWidget *parent = nullptr);