warp-pipe/gui/GraphEditorWidget.cpp

138 lines
4.2 KiB
C++

#include "GraphEditorWidget.h"
#include "WarpGraphModel.h"
#include <QtNodes/BasicGraphicsScene>
#include <QtNodes/GraphicsView>
#include <QInputDialog>
#include <QMenu>
#include <QMessageBox>
#include <QTimer>
#include <QVBoxLayout>
GraphEditorWidget::GraphEditorWidget(warppipe::Client *client,
QWidget *parent)
: QWidget(parent), m_client(client) {
m_model = new WarpGraphModel(client, this);
m_scene = new QtNodes::BasicGraphicsScene(*m_model, this);
m_view = new QtNodes::GraphicsView(m_scene);
auto *layout = new QVBoxLayout(this);
layout->setContentsMargins(0, 0, 0, 0);
layout->addWidget(m_view);
m_view->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_view, &QWidget::customContextMenuRequested, this,
&GraphEditorWidget::onContextMenuRequested);
m_model->refreshFromClient();
m_refreshTimer = new QTimer(this);
connect(m_refreshTimer, &QTimer::timeout, this,
&GraphEditorWidget::onRefreshTimer);
m_refreshTimer->start(500);
}
void GraphEditorWidget::onRefreshTimer() { m_model->refreshFromClient(); }
void GraphEditorWidget::onContextMenuRequested(const QPoint &pos) {
QPointF scenePos = m_view->mapToScene(pos);
uint32_t hitPwNodeId = 0;
for (auto nodeId : m_model->allNodeIds()) {
const WarpNodeData *data = m_model->warpNodeData(nodeId);
if (!data) {
continue;
}
QPointF nodePos =
m_model->nodeData(nodeId, QtNodes::NodeRole::Position).toPointF();
QSize nodeSize =
m_model->nodeData(nodeId, QtNodes::NodeRole::Size).toSize();
QRectF nodeRect(nodePos, QSizeF(nodeSize));
if (nodeRect.contains(scenePos)) {
hitPwNodeId = data->info.id.value;
break;
}
}
QPoint screenPos = m_view->mapToGlobal(pos);
if (hitPwNodeId != 0) {
showNodeContextMenu(screenPos, hitPwNodeId);
} else {
showCanvasContextMenu(screenPos, scenePos);
}
}
void GraphEditorWidget::showCanvasContextMenu(const QPoint &screenPos,
const QPointF &scenePos) {
QMenu menu;
QAction *createSink = menu.addAction(QStringLiteral("Create Virtual Sink"));
QAction *createSource =
menu.addAction(QStringLiteral("Create Virtual Source"));
QAction *chosen = menu.exec(screenPos);
if (chosen == createSink) {
createVirtualNode(true, scenePos);
} else if (chosen == createSource) {
createVirtualNode(false, scenePos);
}
}
void GraphEditorWidget::showNodeContextMenu(const QPoint &screenPos,
uint32_t pwNodeId) {
QtNodes::NodeId qtId = m_model->qtNodeIdForPw(pwNodeId);
const WarpNodeData *data = m_model->warpNodeData(qtId);
if (!data) {
return;
}
WarpNodeType type = WarpGraphModel::classifyNode(data->info);
bool isVirtual =
type == WarpNodeType::kVirtualSink || type == WarpNodeType::kVirtualSource;
if (!isVirtual) {
return;
}
QMenu menu;
QAction *deleteAction = menu.addAction(QStringLiteral("Delete Node"));
QAction *chosen = menu.exec(screenPos);
if (chosen == deleteAction && m_client) {
m_client->RemoveNode(warppipe::NodeId{pwNodeId});
m_model->refreshFromClient();
}
}
void GraphEditorWidget::createVirtualNode(bool isSink,
const QPointF &scenePos) {
QString label = isSink ? QStringLiteral("Create Virtual Sink")
: QStringLiteral("Create Virtual Source");
bool ok = false;
QString name = QInputDialog::getText(this, label,
QStringLiteral("Node name:"),
QLineEdit::Normal, QString(), &ok);
if (!ok || name.trimmed().isEmpty()) {
return;
}
std::string nodeName = name.trimmed().toStdString();
m_model->setPendingPosition(nodeName, scenePos);
warppipe::Status status;
if (isSink) {
auto result = m_client->CreateVirtualSink(nodeName);
status = result.status;
} else {
auto result = m_client->CreateVirtualSource(nodeName);
status = result.status;
}
if (!status.ok()) {
QMessageBox::warning(this, QStringLiteral("Error"),
QString::fromStdString(status.message));
return;
}
m_model->refreshFromClient();
}