Nodes working

This commit is contained in:
Joey Yakimowich-Payne 2026-01-27 16:49:30 -07:00
commit bba5d432f5
3 changed files with 78 additions and 13 deletions

View file

@ -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)) {

View file

@ -8,6 +8,8 @@
#include <QtCore/QStandardPaths>
#include <QtGui/QFont>
#include <QtGui/QFontMetrics>
#include <QtCore/QRectF>
#include <QtCore/QSizeF>
#include <QDir>
#include <QFile>
@ -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<QtNodes::PortIndex>(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<QtNodes::PortIndex>(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<qreal>(maxWidth + 160);
const qreal spacingY = static_cast<qreal>(maxHeight + 120);
for (int i = 0; i < static_cast<int>(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<int>(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<qreal>(maxWidth + 160);
const qreal spacingY = static_cast<qreal>(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<NodeBox> 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);

View file

@ -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;