Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 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
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
67a191d
uniformizes icon files attributes
tatatupi Nov 11, 2025
a41ce83
removes commented code
tatatupi Nov 11, 2025
97c0c94
improves processing status icon resolution
tatatupi Nov 13, 2025
0156e5f
solves situations where icons should not appear
g-abilio Nov 13, 2025
8832922
adds docstring to each nodeprocessingstatus
g-abilio Nov 13, 2025
582cc45
adds possibility to change the node processing status icon style
tatatupi Nov 13, 2025
e73aaf4
moves all status logic to NodeStyle
tatatupi Nov 13, 2025
89eb02f
removes unnecessary code
tatatupi Nov 13, 2025
90ccd88
adds declaration of QPixmap
tatatupi Nov 13, 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
83 changes: 83 additions & 0 deletions examples/calculator/LongProcessingRandomNumber.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
#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);
}
});
}
};
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
59 changes: 50 additions & 9 deletions include/QtNodes/internal/NodeDelegateModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <memory>

#include <QMetaType>
#include <QPixmap>
#include <QtWidgets/QWidget>

#include "Definitions.hpp"
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, ///< No processing status is shown in the Node UI.
Updated = 1, ///< Node is up to date; its outputs reflect the current inputs and parameters.
Processing = 2, ///< Node is currently running a computation.
Pending = 3, ///< Node is out of date and waiting to be recomputed (e.g. manual/queued run).
Empty = 4, ///< Node has no valid input data; nothing to compute.
Failed = 5, ///< The last computation ended with an error.
Partial = 6, ///< Computation finished incompletely; only partial results are available.
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe some use-cases or a short comment could help others?
What is the difference between NoStatus and Empty?
Between Processing and Partial?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The short comments have been added. Thanks for the suggestion!

NoStatus indicates the absence of a processing status for the node in the UI. Empty means that there is no valid input data and therefore nothing to compute.
Processing means that processing is in progress. Partial means that the computation was finished incompletely and only partial results are available.


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,16 @@ class NODE_EDITOR_PUBLIC NodeDelegateModel : public QObject, public Serializable
virtual ConnectionPolicy portConnectionPolicy(PortType, PortIndex) const;

NodeStyle const &nodeStyle() const;

void setNodeStyle(NodeStyle const &style);

QPixmap processingStatusIcon() const;

void setStatusIcon(NodeProcessingStatus status, const QPixmap &pixmap);

void setStatusIconStyle(ProcessingIconStyle const &style);

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 +142,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 +182,11 @@ public Q_SLOTS:
NodeStyle _nodeStyle;

NodeValidationState _nodeValidationState;

NodeProcessingStatus _processingStatus{NodeProcessingStatus::NoStatus};
};

} // namespace QtNodes

Q_DECLARE_METATYPE(QtNodes::NodeValidationState)
Q_DECLARE_METATYPE(QtNodes::NodeProcessingStatus)
1 change: 1 addition & 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
29 changes: 29 additions & 0 deletions include/QtNodes/internal/NodeStyle.hpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
#pragma once

#include <QIcon>
#include <QtGui/QColor>

#include "Export.hpp"
#include "Style.hpp"

namespace QtNodes {

/**
* Describes the position of the processing icon on the node ui
*/
enum class ProcessingIconPos {
BottomLeft = 0, /// icon on the bottom left position
BottomRight = 1, /// icon on the bottom right position
};

/**
* Defines the processing icon style;
*/
struct ProcessingIconStyle
{
ProcessingIconPos _pos{ProcessingIconPos::BottomRight};
double _size{20.0};
double _margin{8.0};
int _resolution{64};
};

class NODE_EDITOR_PUBLIC NodeStyle : public Style
{
public:
Expand Down Expand Up @@ -51,5 +71,14 @@ class NODE_EDITOR_PUBLIC NodeStyle : public Style
float ConnectionPointDiameter;

float Opacity;

QIcon statusUpdated{QStringLiteral("://status_icons/updated.svg")};
QIcon statusProcessing{QStringLiteral("://status_icons/processing.svg")};
QIcon statusPending{QStringLiteral("://status_icons/pending.svg")};
QIcon statusInvalid{QStringLiteral("://status_icons/failed.svg")};
QIcon statusEmpty{QStringLiteral("://status_icons/empty.svg")};
QIcon statusPartial{QStringLiteral("://status_icons/partial.svg")};

ProcessingIconStyle processingIconStyle{};
};
} // namespace QtNodes
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>
12 changes: 12 additions & 0 deletions resources/status_icons/empty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 14 additions & 0 deletions resources/status_icons/failed.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading