From bba5d432f5202f509a12244256a9b3ad339d9c86 Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Tue, 27 Jan 2026 16:49:30 -0700 Subject: [PATCH] Nodes working --- src/gui/GraphEditorWidget.cpp | 4 ++ src/gui/PipeWireGraphModel.cpp | 86 +++++++++++++++++++++++++++++----- src/gui/PipeWireGraphModel.h | 1 + 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/gui/GraphEditorWidget.cpp b/src/gui/GraphEditorWidget.cpp index 5468c5f..cdeb7ac 100644 --- a/src/gui/GraphEditorWidget.cpp +++ b/src/gui/GraphEditorWidget.cpp @@ -140,6 +140,10 @@ GraphEditorWidget::GraphEditorWidget(Potato::PipeWireController *controller, QWi m_view->addAction(resetLayoutAction); syncGraph(); + if (m_model->hasOverlaps()) { + m_model->autoArrange(); + m_model->saveLayout(); + } double viewScale = 1.0; QPointF viewCenter; if (m_model->viewState(viewScale, viewCenter)) { diff --git a/src/gui/PipeWireGraphModel.cpp b/src/gui/PipeWireGraphModel.cpp index e1ea200..2d146ea 100644 --- a/src/gui/PipeWireGraphModel.cpp +++ b/src/gui/PipeWireGraphModel.cpp @@ -8,6 +8,8 @@ #include #include #include +#include +#include #include #include @@ -36,9 +38,9 @@ int nodeWidthFor(const Potato::NodeInfo &info) maxTextWidth = std::max(maxTextWidth, portMetrics.horizontalAdvance(port.name)); } - const int widthPadding = 140; - const int minWidth = 300; - const int maxWidth = 520; + const int widthPadding = 180; + const int minWidth = 320; + const int maxWidth = 700; const int width = maxTextWidth + widthPadding; return std::max(minWidth, std::min(maxWidth, width)); } @@ -194,8 +196,9 @@ QVariant PipeWireGraphModel::nodeData(QtNodes::NodeId nodeId, QtNodes::NodeRole { QFont captionFont; captionFont.setBold(true); - const int width = nodeWidthFor(info) - 40; - return elideLabel(info.name, width, captionFont); + const int width = nodeWidthFor(info) - 50; + const QString title = info.description.isEmpty() ? info.name : info.description; + return elideLabel(title, width, captionFont); } case QtNodes::NodeRole::CaptionVisible: return true; @@ -271,13 +274,13 @@ QVariant PipeWireGraphModel::portData(QtNodes::NodeId nodeId, if (portType == QtNodes::PortType::In) { if (portIndex < static_cast(info.inputPorts.size())) { QFont font; - const int width = nodeWidthFor(info) - 80; + const int width = nodeWidthFor(info) - 100; return elideLabel(info.inputPorts.at(portIndex).name, width, font); } } else if (portType == QtNodes::PortType::Out) { if (portIndex < static_cast(info.outputPorts.size())) { QFont font; - const int width = nodeWidthFor(info) - 80; + const int width = nodeWidthFor(info) - 100; return elideLabel(info.outputPorts.at(portIndex).name, width, font); } } @@ -473,9 +476,19 @@ void PipeWireGraphModel::autoArrange() return left < right; }); - const int columns = 4; - const qreal spacingX = 260.0; - const qreal spacingY = 160.0; + int maxWidth = 0; + int maxHeight = 0; + for (const auto &entry : m_nodes) { + const Potato::NodeInfo &info = entry.second; + maxWidth = std::max(maxWidth, nodeWidthFor(info)); + const int ports = std::max(info.inputPorts.size(), info.outputPorts.size()); + const int height = std::max(110, 70 + (ports * 28)); + maxHeight = std::max(maxHeight, height); + } + + const int columns = 3; + const qreal spacingX = static_cast(maxWidth + 160); + const qreal spacingY = static_cast(maxHeight + 120); for (int i = 0; i < static_cast(ids.size()); ++i) { const int row = i / columns; @@ -621,14 +634,61 @@ QString PipeWireGraphModel::portLabel(const Potato::PortInfo &port) const QPointF PipeWireGraphModel::nextPosition() const { const int index = static_cast(m_positions.size()); - const int columns = 4; - const qreal spacingX = 260.0; - const qreal spacingY = 160.0; + int maxWidth = 0; + int maxHeight = 0; + for (const auto &entry : m_nodes) { + const Potato::NodeInfo &info = entry.second; + maxWidth = std::max(maxWidth, nodeWidthFor(info)); + const int ports = std::max(info.inputPorts.size(), info.outputPorts.size()); + const int height = std::max(110, 70 + (ports * 28)); + maxHeight = std::max(maxHeight, height); + } + + const int columns = 3; + const qreal spacingX = static_cast(maxWidth + 160); + const qreal spacingY = static_cast(maxHeight + 120); const int row = index / columns; const int col = index % columns; return QPointF(col * spacingX, row * spacingY); } +bool PipeWireGraphModel::hasOverlaps() const +{ + struct NodeBox { + QtNodes::NodeId id; + QRectF rect; + }; + + std::vector boxes; + boxes.reserve(m_nodes.size()); + + for (const auto &entry : m_nodes) { + const QtNodes::NodeId nodeId = entry.first; + const auto posIt = m_positions.find(nodeId); + if (posIt == m_positions.end()) { + continue; + } + + const Potato::NodeInfo &info = entry.second; + const int width = nodeWidthFor(info); + const int ports = std::max(info.inputPorts.size(), info.outputPorts.size()); + const int height = std::max(110, 70 + (ports * 28)); + + QRectF rect(posIt->second, QSizeF(width, height)); + boxes.push_back({nodeId, rect}); + } + + for (size_t i = 0; i < boxes.size(); ++i) { + for (size_t j = i + 1; j < boxes.size(); ++j) { + if (boxes[i].rect.intersects(boxes[j].rect)) { + return true; + } + } + } + + return false; +} + QString PipeWireGraphModel::layoutFilePath() const { const QString baseDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); diff --git a/src/gui/PipeWireGraphModel.h b/src/gui/PipeWireGraphModel.h index 3ea7a6b..01d3e02 100644 --- a/src/gui/PipeWireGraphModel.h +++ b/src/gui/PipeWireGraphModel.h @@ -57,6 +57,7 @@ public: const Potato::NodeInfo *nodeInfo(QtNodes::NodeId nodeId) const; bool connectionIdForLink(const Potato::LinkInfo &link, QtNodes::ConnectionId &connectionId) const; bool updatePipeWireNode(const Potato::NodeInfo &node); + bool hasOverlaps() const; void reset(); void loadLayout(); void saveLayout() const;