Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2edfb0b
Updates fork from upstream
tatatupi Jun 20, 2025
988ce45
wip: adds NodeValidationState info to NodeDelegateModel
tatatupi Jun 22, 2025
1c84750
makes the nodeObject red in case of invalid state and adds a tooltip …
tatatupi Jun 22, 2025
3007c23
adds warning state and adapts calculator example
tatatupi Jun 22, 2025
129d414
adds validation icon and adapts calculation example
tatatupi Jun 22, 2025
e0b0c4a
core improvements to develop node processing status
g-abilio Jul 14, 2025
e002f5b
first commit on the creation of a processing status example
g-abilio Jul 15, 2025
985b638
fixes nodeprocessingstatus cast
tatatupi Jul 15, 2025
3f55e35
creation of random gen example, and fix of icon color
g-abilio Jul 16, 2025
50c6bec
Connect delegate UI update signal
tatatupi Jul 17, 2025
1c09ecf
fix random number node dynamic
g-abilio Jul 17, 2025
50ce760
Merge pull request #5 from fabns-nano/codex/add-signal-for-ui-updates…
g-abilio Jul 17, 2025
f2c120f
clean up test code in multiplication node
g-abilio Jul 17, 2025
965eb15
Add per-node background color API
hudsonmiranda291 Jul 22, 2025
97d48d5
Merge branch 'paceholder:master' into master
tatatupi Sep 2, 2025
89ac7f2
Merge branch 'master' of https://github.com/paceholder/nodeeditor
tatatupi Sep 5, 2025
37c3bf8
solves conflict
tatatupi Sep 10, 2025
b23ecc3
revert unnecessary changes in multiplication model
tatatupi Sep 10, 2025
0a35f76
revert unnecessary changes
tatatupi Sep 10, 2025
a9be092
solve icon size and refactor NodeProcessingStatus code
g-abilio Sep 11, 2025
5530b72
update and merge new code
g-abilio Sep 11, 2025
03e311a
remove duplicate code
g-abilio Sep 11, 2025
a87ceb2
add space to better organize processing status in node display
g-abilio Sep 15, 2025
ae3715b
remove processing value default value
g-abilio Sep 19, 2025
eedc666
fix bugs in node processing status
g-abilio Sep 19, 2025
1298605
add Q_DECLARE_METATYPE to solve linux build problems
g-abilio Sep 24, 2025
47d948f
declaring metatype in the correct place
g-abilio Sep 24, 2025
21b55ac
Merge pull request #6 from fabns-nano/node_processing_status
g-abilio Oct 20, 2025
4f1b23c
fix undocommands module inclusion
g-abilio Dec 3, 2025
87e219b
solve conflicts
g-abilio Dec 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions examples/calculator/DivisionModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,23 +59,23 @@ class DivisionModel : public MathOperationDataModel
if (n2 && (n2->number() == 0.0)) {
state._state = QtNodes::NodeValidationState::State::Error;
state._stateMessage = QStringLiteral("Division by zero error");
setValidatonState(state);
setValidationState(state);
_result.reset();
} else if ( n2 && (n2->number() < 1e-5)) {
state._state = QtNodes::NodeValidationState::State::Warning;
state._stateMessage = QStringLiteral("Very small divident. Result might overflow");
setValidatonState(state);
setValidationState(state);
if (n1) {
_result = std::make_shared<DecimalData>(n1->number() / n2->number());
} else {
_result.reset();
}
} else if (n1 && n2) {
setValidatonState(state);
setValidationState(state);
_result = std::make_shared<DecimalData>(n1->number() / n2->number());
} else {
QtNodes::NodeValidationState state;
setValidatonState(state);
setValidationState(state);
_result.reset();
}

Expand Down
82 changes: 82 additions & 0 deletions examples/calculator/LongProcessingRandomNumber.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#pragma once

#include <QtNodes/NodeDelegateModel>
#include <QTimer>
#include <QtCore/QObject>
#include <QtWidgets/QLabel>
#include <QtCore/QRandomGenerator64>

#include "MathOperationDataModel.hpp"
#include "DecimalData.hpp"

/// The model generates a random value in a long processing schema,
/// as it should demonstrate the usage of the NodeProcessingStatus.
/// The random number is generate in the [n1, n2] interval.
class RandomNumberModel : public MathOperationDataModel
{
public:
RandomNumberModel() {
this->setNodeProcessingStatus(QtNodes::NodeProcessingStatus::Empty);

QObject::connect(this, &NodeDelegateModel::computingStarted, this, [this]() {
if (_number1.lock() && _number2.lock()) {
this->setNodeProcessingStatus(
QtNodes::NodeProcessingStatus::Processing);
}

emit requestNodeUpdate();
});
QObject::connect(this, &NodeDelegateModel::computingFinished, this, [this]() {
this->setNodeProcessingStatus(
QtNodes::NodeProcessingStatus::Updated);

emit requestNodeUpdate();
});
}
virtual ~RandomNumberModel() {}

public:
QString caption() const override { return QStringLiteral("Random Number"); }

QString name() const override { return QStringLiteral("Random Number"); }

private:
void compute() override
{
Q_EMIT computingStarted();
PortIndex const outPortIndex = 0;

auto n1 = _number1.lock();
auto n2 = _number2.lock();

QTimer *timer = new QTimer(this);
timer->start(1000);
int secondsRemaining = 3;
connect(timer, &QTimer::timeout, this, [=]() mutable {
if (--secondsRemaining <= 0) {
timer->stop();
if (n1 && n2) {
double a = n1->number();
double b = n2->number();

if (a > b) {
setNodeProcessingStatus(QtNodes::NodeProcessingStatus::Failed);

emit requestNodeUpdate();
return;
}

double upper = std::nextafter(b, std::numeric_limits<double>::max());
double randomValue = QRandomGenerator::global()->generateDouble() * (upper - a) + a;

_result = std::make_shared<DecimalData>(randomValue);
Q_EMIT computingFinished();
} else {
_result.reset();
}

Q_EMIT dataUpdated(outPortIndex);
}
});
}
};
4 changes: 3 additions & 1 deletion examples/calculator/NumberDisplayDataModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

NumberDisplayDataModel::NumberDisplayDataModel()
: _label{nullptr}
{}
{
this->setNodeProcessingStatus(QtNodes::NodeProcessingStatus::NoStatus);
}

unsigned int NumberDisplayDataModel::nPorts(PortType portType) const
{
Expand Down
4 changes: 3 additions & 1 deletion examples/calculator/NumberSourceDataModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
NumberSourceDataModel::NumberSourceDataModel()
: _lineEdit{nullptr}
, _number(std::make_shared<DecimalData>(0.0))
{}
{
this->setNodeProcessingStatus(QtNodes::NodeProcessingStatus::NoStatus);
}

QJsonObject NumberSourceDataModel::save() const
{
Expand Down
3 changes: 3 additions & 0 deletions examples/calculator/headless_main.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include "AdditionModel.hpp"
#include "DivisionModel.hpp"
#include "LongProcessingRandomNumber.hpp"
#include "MultiplicationModel.hpp"
#include "NumberDisplayDataModel.hpp"
#include "NumberSourceDataModel.hpp"
Expand Down Expand Up @@ -27,6 +28,8 @@ static std::shared_ptr<NodeDelegateModelRegistry> registerDataModels()

ret->registerModel<DivisionModel>("Operators");

ret->registerModel<RandomNumberModel>("Operators");

return ret;
}

Expand Down
3 changes: 3 additions & 0 deletions examples/calculator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "AdditionModel.hpp"
#include "DivisionModel.hpp"
#include "LongProcessingRandomNumber.hpp"
#include "MultiplicationModel.hpp"
#include "NumberDisplayDataModel.hpp"
#include "NumberSourceDataModel.hpp"
Expand All @@ -40,6 +41,8 @@ static std::shared_ptr<NodeDelegateModelRegistry> registerDataModels()

ret->registerModel<DivisionModel>("Operators");

ret->registerModel<RandomNumberModel>("Operators");

return ret;
}

Expand Down
2 changes: 2 additions & 0 deletions include/QtNodes/internal/DefaultNodePainter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class NODE_EDITOR_PUBLIC DefaultNodePainter : public AbstractNodePainter

void drawResizeRect(QPainter *painter, NodeGraphicsObject &ngo) const;

void drawProcessingIndicator(QPainter *painter, NodeGraphicsObject &ngo) const;

void drawValidationIcon(QPainter *painter, NodeGraphicsObject &ngo) const;

private:
Expand Down
1 change: 1 addition & 0 deletions include/QtNodes/internal/Definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ enum class NodeRole {
OutPortCount = 9, ///< `unsigned int`
Widget = 10, ///< Optional `QWidget*` or `nullptr`
ValidationState = 11, ///< Enum NodeValidationState of the node
ProcessingStatus = 12 ///< Enum NodeProcessingStatus of the node
};
Q_ENUM_NS(NodeRole)

Expand Down
56 changes: 47 additions & 9 deletions include/QtNodes/internal/NodeDelegateModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include "Export.hpp"
#include "NodeData.hpp"
#include "NodeStyle.hpp"
#include <QtGui/QColor>
#include "Serializable.hpp"

namespace QtNodes {
Expand All @@ -19,9 +20,9 @@ namespace QtNodes {
struct NodeValidationState
{
enum class State : int {
Valid = 0, ///< All required inputs are present and correct.
Warning = 1, ///< Some inputs are missing or questionable, processing may be unreliable.
Error = 2, ///< Inputs or settings are invalid, preventing successful computation.
Valid = 0, ///< All required inputs are present and correct.
Warning = 1, ///< Some inputs are missing or questionable, processing may be unreliable.
Error = 2, ///< Inputs or settings are invalid, preventing successful computation.
};
bool isValid() { return _state == State::Valid; };
QString const message() { return _stateMessage; }
Expand All @@ -31,6 +32,19 @@ struct NodeValidationState
QString _stateMessage{""};
};

/**
* Describes the node status, depending on its current situation
*/
enum class NodeProcessingStatus : int {
NoStatus = 0, ///
Updated = 1, ///
Processing = 2, ///
Pending = 3, ///
Empty = 4, ///
Failed = 5, ///
Partial = 6, ///
};

class StyleCollection;

/**
Expand All @@ -39,7 +53,9 @@ class StyleCollection;
* AbstractGraphModel.
* This class is the same what has been called NodeDataModel before v3.
*/
class NODE_EDITOR_PUBLIC NodeDelegateModel : public QObject, public Serializable
class NODE_EDITOR_PUBLIC NodeDelegateModel
: public QObject
, public Serializable
{
Q_OBJECT

Expand All @@ -48,15 +64,15 @@ class NODE_EDITOR_PUBLIC NodeDelegateModel : public QObject, public Serializable

virtual ~NodeDelegateModel() = default;

/// It is possible to hide caption in GUI
virtual bool captionVisible() const { return true; }

/// Name makes this model unique
virtual QString name() const = 0;

/// Caption is used in GUI
virtual QString caption() const = 0;

/// It is possible to hide caption in GUI
virtual bool captionVisible() const { return true; }

/// Port caption is used in GUI to label individual ports
virtual QString portCaption(PortType, PortIndex) const { return QString(); }

Expand All @@ -66,12 +82,16 @@ class NODE_EDITOR_PUBLIC NodeDelegateModel : public QObject, public Serializable
/// Validation State will default to Valid, but you can manipulate it by overriding in an inherited class
virtual NodeValidationState validationState() const { return _nodeValidationState; }

public:
/// Returns the curent processing status
virtual NodeProcessingStatus processingStatus() const { return _processingStatus; }

QJsonObject save() const override;

void load(QJsonObject const &) override;

void setValidatonState(const NodeValidationState &validationState);
void setValidationState(const NodeValidationState &validationState);

void setNodeProcessingStatus(NodeProcessingStatus status);

virtual unsigned int nPorts(PortType portType) const = 0;

Expand All @@ -80,8 +100,13 @@ class NODE_EDITOR_PUBLIC NodeDelegateModel : public QObject, public Serializable
virtual ConnectionPolicy portConnectionPolicy(PortType, PortIndex) const;

NodeStyle const &nodeStyle() const;

void setNodeStyle(NodeStyle const &style);

/// Convenience helper to change the node background color.
void setBackgroundColor(QColor const &color);

public:
virtual void setInData(std::shared_ptr<NodeData> nodeData, PortIndex const portIndex) = 0;

virtual std::shared_ptr<NodeData> outData(PortIndex const port) = 0;
Expand Down Expand Up @@ -114,10 +139,20 @@ public Q_SLOTS:
void dataInvalidated(PortIndex const index);

void computingStarted();

void computingFinished();

void embeddedWidgetSizeUpdated();

/// Request an update of the node's UI.
/**
* Emit this signal whenever some internal state change requires
* the node to be repainted. The containing graph model will
* propagate the update to the scene.
*/
void requestNodeUpdate();

/// Call this function before deleting the data associated with ports.
/**
* @brief Call this function before deleting the data associated with ports.
* The function notifies the Graph Model and makes it remove and recompute the
Expand All @@ -144,8 +179,11 @@ public Q_SLOTS:
NodeStyle _nodeStyle;

NodeValidationState _nodeValidationState;

NodeProcessingStatus _processingStatus;
};

} // namespace QtNodes

Q_DECLARE_METATYPE(QtNodes::NodeValidationState)
Q_DECLARE_METATYPE(QtNodes::NodeProcessingStatus)
20 changes: 20 additions & 0 deletions include/QtNodes/internal/NodeGraphicsObject.hpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <QIcon>
#include <QtCore/QUuid>
#include <QtWidgets/QGraphicsObject>

Expand Down Expand Up @@ -52,6 +53,14 @@ class NodeGraphicsObject : public QGraphicsObject

void updateQWidgetEmbedPos();

void updateStatusIconSize() const;

const QIcon processingStatusIcon() const;

QRect statusIconRect() const;

QSize statusIconSize() const;

protected:
void paint(QPainter *painter,
QStyleOptionGraphicsItem const *option,
Expand Down Expand Up @@ -81,5 +90,16 @@ class NodeGraphicsObject : public QGraphicsObject

// either nullptr or owned by parent QGraphicsItem
QGraphicsProxyWidget *_proxyWidget;

mutable bool _statusIconActive;

mutable QSize _statusIconSize;

const QIcon _statusUpdated{"://status_icons/updated.svg"};
const QIcon _statusProcessing{"://status_icons/processing.svg"};
const QIcon _statusPending{"://status_icons/pending.svg"};
const QIcon _statusInvalid{"://status_icons/failed.svg"};
const QIcon _statusEmpty{"://status_icons/empty.svg"};
const QIcon _statusPartial{"://status_icons/partial.svg"};
};
} // namespace QtNodes
6 changes: 6 additions & 0 deletions include/QtNodes/internal/NodeStyle.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ class NODE_EDITOR_PUBLIC NodeStyle : public Style

QJsonObject toJson() const override;

/// Set uniform background color for the node.
void setBackgroundColor(QColor const &color);

/// Current uniform background color.
QColor backgroundColor() const;

public:
QColor NormalBoundaryColor;
QColor SelectedBoundaryColor;
Expand Down
2 changes: 1 addition & 1 deletion include/QtNodes/internal/UndoCommands.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
#include "Definitions.hpp"
#include "Export.hpp"

#include <QUndoCommand>
#include <QtCore/QJsonObject>
#include <QtCore/QPointF>
#include <QUndoCommand>

#include <unordered_set>

Expand Down
6 changes: 6 additions & 0 deletions resources/resources.qrc
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,11 @@
<qresource prefix="/">
<file>DefaultStyle.json</file>
<file>info-tooltip.svg</file>
<file>status_icons/empty.svg</file>
<file>status_icons/failed.svg</file>
<file>status_icons/partial.svg</file>
<file>status_icons/pending.svg</file>
<file>status_icons/processing.svg</file>
<file>status_icons/updated.svg</file>
</qresource>
</RCC>
Loading
Loading