Skip to content
Open
Show file tree
Hide file tree
Changes from 12 commits
Commits
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
1 change: 1 addition & 0 deletions examples/calculator/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ set(CALC_HEADER_FILES
NumberDisplayDataModel.hpp
NumberSourceDataModel.hpp
SubtractionModel.hpp
LongProcessingRandomNumber.hpp
)

add_executable(calculator
Expand Down
103 changes: 73 additions & 30 deletions examples/calculator/LongProcessingRandomNumber.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
#include <QtNodes/NodeDelegateModel>
#include <QTimer>
#include <QtCore/QObject>
#include <QtCore/QElapsedTimer>
#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 model generates a random value in a long processing schema, as it should demonstrate
/// the usage of the NodeProcessingStatus and the ProgressValue functionality.
/// The random number is generate in the [n1, n2] interval.
class RandomNumberModel : public MathOperationDataModel
{
Expand All @@ -20,21 +21,53 @@ class RandomNumberModel : public MathOperationDataModel


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

setProgressValue(QString{"0%"});
emit requestNodeUpdate();

_elapsedTimer.start();

if (!_progressTimer) {
_progressTimer = new QTimer(this);
connect(_progressTimer, &QTimer::timeout, this, [this]() {
qint64 elapsed = _elapsedTimer.elapsed();
int percent = static_cast<int>((double(elapsed) / _totalDurationMs) * 100.0);

if (percent > 100)
percent = 100;

setProgressValue(QString::number(percent) + "%");
emit requestNodeUpdate();
});
}

_progressTimer->start(_progressUpdateIntervalMs);

emit requestNodeUpdate();
});

QObject::connect(this, &NodeDelegateModel::computingFinished, this, [this]() {
if (_progressTimer) {
_progressTimer->stop();
}

setProgressValue(QString());

this->setNodeProcessingStatus(
QtNodes::NodeProcessingStatus::Updated);

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

virtual ~RandomNumberModel() {
if (_progressTimer) {
_progressTimer->stop();
delete _progressTimer;
}
}

public:
QString caption() const override { return QStringLiteral("Random Number"); }
Expand All @@ -44,40 +77,50 @@ class RandomNumberModel : public MathOperationDataModel
private:
void compute() override
{
auto n1 = _number1.lock();
auto n2 = _number2.lock();

if (!n1 || !n2) {
return;
}

Q_EMIT computingStarted();
PortIndex const outPortIndex = 0;

auto n1 = _number1.lock();
auto n2 = _number2.lock();
QTimer::singleShot(_totalDurationMs, this, [this, n1, n2]() {
if (n1 && n2) {
double a = n1->number();
double b = n2->number();

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

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;
if (_progressTimer) {
_progressTimer->stop();
}

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

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

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

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

Q_EMIT dataUpdated(outPortIndex);
});
}

QTimer *_progressTimer = nullptr;
QElapsedTimer _elapsedTimer;

const int _totalDurationMs = 3000;
const int _progressUpdateIntervalMs = 50;
};
2 changes: 2 additions & 0 deletions include/QtNodes/internal/DefaultNodePainter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ class NODE_EDITOR_PUBLIC DefaultNodePainter : public AbstractNodePainter

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

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

private:
QIcon _toolTipIcon{"://info-tooltip.svg"};
};
Expand Down
31 changes: 16 additions & 15 deletions include/QtNodes/internal/Definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,23 +18,24 @@ NODE_EDITOR_PUBLIC Q_NAMESPACE
Q_NAMESPACE_EXPORT(NODE_EDITOR_PUBLIC)
#endif

/**
/**
* Constants used for fetching QVariant data from GraphModel.
*/
enum class NodeRole {
Type = 0, ///< Type of the current node, usually a string.
Position = 1, ///< `QPointF` positon of the node on the scene.
Size = 2, ///< `QSize` for resizable nodes.
CaptionVisible = 3, ///< `bool` for caption visibility.
Caption = 4, ///< `QString` for node caption.
Style = 5, ///< Custom NodeStyle as QJsonDocument
InternalData = 6, ///< Node-stecific user data as QJsonObject
InPortCount = 7, ///< `unsigned int`
OutPortCount = 9, ///< `unsigned int`
Widget = 10, ///< Optional `QWidget*` or `nullptr`
ValidationState = 11, ///< Enum NodeValidationState of the node
ProcessingStatus = 12 ///< Enum NodeProcessingStatus of the node
};
enum class NodeRole {
Type = 0, ///< Type of the current node, usually a string.
Position = 1, ///< `QPointF` positon of the node on the scene.
Size = 2, ///< `QSize` for resizable nodes.
CaptionVisible = 3, ///< `bool` for caption visibility.
Caption = 4, ///< `QString` for node caption.
Style = 5, ///< Custom NodeStyle as QJsonDocument
InternalData = 6, ///< Node-stecific user data as QJsonObject
InPortCount = 7, ///< `unsigned int`
OutPortCount = 9, ///< `unsigned int`
Widget = 10, ///< Optional `QWidget*` or `nullptr`
ValidationState = 11, ///< Enum NodeValidationState of the node
ProcessingStatus = 12, ///< Enum NodeProcessingStatus of the node
ProgressValue = 13, ///< 'QString' for the progress value
};
Q_ENUM_NS(NodeRole)

/**
Expand Down
8 changes: 8 additions & 0 deletions include/QtNodes/internal/NodeDelegateModel.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ class NODE_EDITOR_PUBLIC NodeDelegateModel
/// Returns the curent processing status
virtual NodeProcessingStatus processingStatus() const { return _processingStatus; }

/// Progress is used in GUI
virtual QString progressValue() const { return _progressValue; }

public:
QJsonObject save() const override;

void load(QJsonObject const &) override;
Expand All @@ -109,6 +113,8 @@ class NODE_EDITOR_PUBLIC NodeDelegateModel

void setStatusIconStyle(ProcessingIconStyle const &style);

void setProgressValue(QString new_progress) { _progressValue = new_progress; }

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

Expand Down Expand Up @@ -184,6 +190,8 @@ public Q_SLOTS:
NodeValidationState _nodeValidationState;

NodeProcessingStatus _processingStatus{NodeProcessingStatus::NoStatus};

QString _progressValue{QString()};
};

} // namespace QtNodes
Expand Down
8 changes: 7 additions & 1 deletion src/DataFlowGraphModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,10 @@ QVariant DataFlowGraphModel::nodeData(NodeId nodeId, NodeRole role) const
auto processingStatus = model->processingStatus();
result = QVariant::fromValue(processingStatus);
} break;

case NodeRole::ProgressValue:
result = model->progressValue();
break;
}

return result;
Expand Down Expand Up @@ -382,8 +386,10 @@ bool DataFlowGraphModel::setNodeData(NodeId nodeId, NodeRole role, QVariant valu
}
Q_EMIT nodeUpdated(nodeId);
} break;
}

case NodeRole::ProgressValue:
break;
}
return result;
}

Expand Down
1 change: 1 addition & 0 deletions src/DefaultHorizontalNodeGeometry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ void DefaultHorizontalNodeGeometry::recomputeSize(NodeId const nodeId) const
height += _portSpasing; // space below caption

QVariant var = _graphModel.nodeData(nodeId, NodeRole::ProcessingStatus);

auto processingStatusValue = var.value<int>();

if (processingStatusValue != 0)
Expand Down
29 changes: 29 additions & 0 deletions src/DefaultNodePainter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ void DefaultNodePainter::paint(QPainter *painter, NodeGraphicsObject &ngo) const
drawResizeRect(painter, ngo);

drawValidationIcon(painter, ngo);

drawProgressValue(painter, ngo);
}

void DefaultNodePainter::drawNodeRect(QPainter *painter, NodeGraphicsObject &ngo) const
Expand Down Expand Up @@ -375,4 +377,31 @@ void DefaultNodePainter::drawValidationIcon(QPainter *painter, NodeGraphicsObjec
painter->restore();
}

void DefaultNodePainter::drawProgressValue(QPainter *painter, NodeGraphicsObject &ngo) const
{
AbstractGraphModel &model = ngo.graphModel();
NodeId const nodeId = ngo.nodeId();
AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();

QString const nodeProgress = model.nodeData(nodeId, NodeRole::ProgressValue).toString();

QFont font = painter->font();
font.setBold(true);
font.setPointSize(5);
auto rect = QFontMetrics(font).boundingRect(nodeProgress);

QSize size = geometry.size(nodeId);
QPointF position(rect.width() / 4.0, size.height() - 0.5 * rect.height());

QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
NodeStyle nodeStyle(json.object());

painter->setFont(font);
painter->setPen(nodeStyle.FontColor);
painter->drawText(position, nodeProgress);

font.setBold(false);
painter->setFont(font);
}

} // namespace QtNodes
Loading