From 08fee50d12bcf70a94eeb57192be492aca845e2f Mon Sep 17 00:00:00 2001 From: Joey Yakimowich-Payne Date: Sat, 31 Jan 2026 11:36:06 -0700 Subject: [PATCH] Fix sisyphus path --- .gitignore | 1 + .../warppipe-node-editor/learnings.md | 345 ------------------ 2 files changed, 1 insertion(+), 345 deletions(-) delete mode 100644 .sisyphus/notepads/warppipe-node-editor/learnings.md diff --git a/.gitignore b/.gitignore index 0e17073..54605b7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.sisyphus /build/ /build-*/ /cmake-build-*/ diff --git a/.sisyphus/notepads/warppipe-node-editor/learnings.md b/.sisyphus/notepads/warppipe-node-editor/learnings.md deleted file mode 100644 index 5d041e7..0000000 --- a/.sisyphus/notepads/warppipe-node-editor/learnings.md +++ /dev/null @@ -1,345 +0,0 @@ -## QtNodes (nodeeditor) Library Research - 2026-01-29 - -### Library Overview -- **Repository**: https://github.com/paceholder/nodeeditor -- **License**: BSD-3-Clause -- **Latest Version**: 3.0.x (major rewrite from v2.x) -- **Qt Support**: Qt 5.15+ and Qt 6.x -- **Documentation**: https://qtnodes.readthedocs.io/ - -### Key Architecture Concepts -1. **Model-View Approach**: Graph structure defined by classes derived from `AbstractGraphModel` -2. **Headless Mode**: Can create/modify graphs without GUI (useful for testing/processing) -3. **Two Main Workflows**: - - Pure graph visualization (AbstractGraphModel) - - Data propagation (DataFlowGraphModel) - -### CMake Integration -```cmake -# Build options -cmake .. -DUSE_QT6=on # or off for Qt5 -cmake .. -DBUILD_SHARED_LIBS=off # for static lib - -# Dependencies -- Qt >5.15 -- CMake 3.8+ -- Catch2 (for tests, optional) -``` - -### Creating Custom Node Types - -#### 1. Derive from NodeDelegateModel -```cpp -class MyCustomNode : public QtNodes::NodeDelegateModel { - Q_OBJECT -public: - QString name() const override { return "MyNodeType"; } - QString caption() const override { return "My Node"; } - - // Define ports - unsigned int nPorts(PortType portType) const override; - NodeDataType dataType(PortType portType, PortIndex index) const override; - - // Data handling - void setInData(std::shared_ptr data, PortIndex port) override; - std::shared_ptr outData(PortIndex port) override; - - // Optional: Embed Qt widget - QWidget* embeddedWidget() override { return _myWidget; } - - // Optional: Make resizable - bool resizable() const override { return true; } -}; -``` - -#### 2. Register with NodeDelegateModelRegistry -```cpp -auto registry = std::make_shared(); -registry->registerModel("Category"); -``` - -#### 3. Create DataFlowGraphModel -```cpp -auto model = std::make_shared(registry); -``` - -### Port Management - -#### Port Types -```cpp -enum class PortType { In, Out }; -``` - -#### Defining Ports -```cpp -unsigned int MyNode::nPorts(PortType portType) const { - if (portType == PortType::In) return 2; // 2 input ports - return 1; // 1 output port -} - -NodeDataType MyNode::dataType(PortType portType, PortIndex index) const { - return {"audio", "Audio Stream"}; // {id, name} -} -``` - -#### Dynamic Ports -Use these signals to add/remove ports at runtime: -```cpp -portsAboutToBeInserted(nodeId, PortType::Out, startIndex, endIndex); -// Modify underlying data -portsInserted(); - -portsAboutToBeDeleted(nodeId, PortType::In, startIndex, endIndex); -// Modify underlying data -portsDeleted(); -``` - -### Connection Management - -#### Connection Structure -```cpp -struct ConnectionId { - NodeId outNodeId; - PortIndex outPortIndex; - NodeId inNodeId; - PortIndex inPortIndex; -}; -``` - -#### Creating Connections -```cpp -// Programmatically -ConnectionId connId{sourceNode, 0, targetNode, 0}; -model->addConnection(connId); - -// Check if possible -if (model->connectionPossible(connId)) { - model->addConnection(connId); -} -``` - -#### Connection Policies -```cpp -enum class ConnectionPolicy { - One, // Only one connection per port - Many // Multiple connections allowed -}; - -// Return from nodeData with PortRole::ConnectionPolicyRole -``` - -### Data Propagation - -#### Data Flow Chain -1. Source node emits `dataUpdated(PortIndex)` -2. `DataFlowGraphModel::onOutPortDataUpdated()` triggered -3. Data fetched via `outData(portIndex)` -4. Data set to connected nodes via `setInData(data, portIndex)` -5. Signal `inPortDataWasSet()` emitted - -#### Custom Data Types -```cpp -class MyAudioData : public NodeData { -public: - NodeDataType type() const override { - return {"audio", "Audio Stream"}; - } - - // Your data members - std::vector samples; - int sampleRate; -}; -``` - -### Styling and Customization - -#### Style Classes -- `NodeStyle`: Node appearance (colors, borders, shadows) -- `ConnectionStyle`: Connection lines (colors, width) -- `GraphicsViewStyle`: Background grid colors - -#### Accessing Styles -```cpp -#include - -auto& nodeStyle = StyleCollection::nodeStyle(); -auto& connStyle = StyleCollection::connectionStyle(); -``` - -#### JSON Style Format -```json -{ - "NodeStyle": { - "NormalBoundaryColor": [255, 255, 255], - "SelectedBoundaryColor": [255, 165, 0], - "GradientColor0": "gray", - "ShadowColor": [20, 20, 20], - "FontColor": "white", - "ConnectionPointColor": [169, 169, 169], - "PenWidth": 1.0, - "Opacity": 0.8 - } -} -``` - -### Event Handling - -#### Context Menus -```cpp -// GraphicsView level -void MyGraphicsView::contextMenuEvent(QContextMenuEvent* event) override; - -// Node level - connect to signal -connect(scene, &BasicGraphicsScene::nodeContextMenu, - [](NodeId nodeId, QPointF scenePos) { - // Show custom menu - }); -``` - -#### Node Events -Available signals from BasicGraphicsScene: -- `nodeClicked(NodeId)` -- `nodeDoubleClicked(NodeId)` -- `nodeContextMenu(NodeId, QPointF)` -- `nodeHovered(NodeId, QPoint)` -- `nodeHoverLeft(NodeId)` - -### Scene Setup - -#### Basic Setup -```cpp -#include -#include -#include - -auto registry = registerMyNodes(); -auto model = std::make_shared(registry); -auto scene = new DataFlowGraphicsScene(*model); -auto view = new GraphicsView(scene); - -view->show(); -``` - -#### Undo/Redo Support -```cpp -// Scene has built-in QUndoStack -scene->undoStack().undo(); -scene->undoStack().redo(); - -// Keyboard shortcuts (built-in) -// Ctrl+Z: Undo -// Ctrl+Shift+Z: Redo -// Ctrl+D: Duplicate -``` - -### Serialization - -#### Save/Load Graph -```cpp -// Save -QJsonObject json = model->save(); -QJsonDocument doc(json); -QFile file("graph.json"); -file.open(QIODevice::WriteOnly); -file.write(doc.toJson()); - -// Load -QFile file("graph.json"); -file.open(QIODevice::ReadOnly); -QJsonDocument doc = QJsonDocument::fromJson(file.readAll()); -model->load(doc.object()); -``` - -#### Custom Node Serialization -```cpp -QJsonObject MyNode::save() const override { - QJsonObject obj = NodeDelegateModel::save(); - obj["custom-data"] = _myCustomValue; - return obj; -} - -void MyNode::load(QJsonObject const& obj) override { - _myCustomValue = obj["custom-data"].toInt(); -} -``` - -### Layout Options - -#### Horizontal (Default) -``` - ------- -o | Caption -o | - ------- -``` - -#### Vertical -``` - -------o-------------o------- -| PortCaption PortCaption | -| Node Caption | -| PortCaption | - --------------o-------------- -``` - -Use `DefaultVerticalNodeGeometry` instead of `DefaultHorizontalNodeGeometry`. - -### Advanced Features - -#### Locked Nodes -```cpp -NodeFlags MyModel::nodeFlags(NodeId nodeId) const override { - auto flags = DataFlowGraphModel::nodeFlags(nodeId); - if (shouldLock) flags |= NodeFlag::Locked; - return flags; -} -``` - -#### Disable Connection Detaching -```cpp -bool MyModel::detachPossible(ConnectionId const& id) const override { - return false; // Prevent detaching -} -``` - -#### Embedded Widgets -```cpp -QWidget* MyNode::embeddedWidget() override { - if (!_widget) { - _widget = new QSlider(Qt::Horizontal); - connect(_widget, &QSlider::valueChanged, [this](int val) { - // Update and propagate data - Q_EMIT dataUpdated(0); - }); - } - return _widget; -} -``` - -### Example References -- `examples/calculator/`: Basic data flow with math operations -- `examples/dynamic_ports/`: Adding/removing ports at runtime -- `examples/styles/`: Custom styling -- `examples/vertical_layout/`: Vertical node layout -- `examples/lock_nodes_and_connections/`: Node locking -- `examples/headless_main.cpp`: Using without GUI - -### Key Classes Summary -- `AbstractGraphModel`: Base graph model -- `DataFlowGraphModel`: Graph with data propagation -- `NodeDelegateModel`: Custom node implementation -- `NodeDelegateModelRegistry`: Node type registration -- `BasicGraphicsScene`: Scene management -- `DataFlowGraphicsScene`: Scene with data flow -- `GraphicsView`: View widget -- `NodeData`: Base class for data types -- `StyleCollection`: Centralized styling - -### Important Notes for Audio Routing -1. Use `ConnectionPolicy::Many` for audio ports (multiple connections) -2. Consider using `std::shared_ptr` for data sharing -3. Implement proper sample rate/buffer size handling in data types -4. Use embedded widgets for gain controls, meters, etc. -5. Consider headless mode for audio processing thread -6. Implement proper serialization for saving/loading patches -