Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
118 changes: 78 additions & 40 deletions examples/calculator/LongProcessingRandomNumber.hpp
Original file line number Diff line number Diff line change
@@ -1,37 +1,72 @@
#pragma once

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

#include "MathOperationDataModel.hpp"
#include "DecimalData.hpp"
#include "MathOperationDataModel.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
class LongProcessingRandomNumber : public MathOperationDataModel
{
public:
RandomNumberModel()
: _timer(new QTimer(this))
LongProcessingRandomNumber()
{
this->setNodeProcessingStatus(QtNodes::NodeProcessingStatus::Empty);

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

public:
QString caption() const override { return QStringLiteral("Random Number"); }
Expand All @@ -41,47 +76,50 @@ class RandomNumberModel : public MathOperationDataModel
private:
void compute() override
{
// Stop any previous computation
_timer->stop();
_timer->disconnect();
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);

_secondsRemaining = 3;
_timer->start(1000);
connect(_timer, &QTimer::timeout, this, [this, n1, n2, outPortIndex]() {
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);
});
}

private:
QTimer *_timer;
int _secondsRemaining = 0;
QTimer *_progressTimer = nullptr;
QElapsedTimer _elapsedTimer;

const int _totalDurationMs = 3000;
const int _progressUpdateIntervalMs = 50;
};
2 changes: 1 addition & 1 deletion examples/calculator/headless_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ static std::shared_ptr<NodeDelegateModelRegistry> registerDataModels()

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

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

return ret;
}
Expand Down
2 changes: 1 addition & 1 deletion examples/calculator/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ static std::shared_ptr<NodeDelegateModelRegistry> registerDataModels()

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

ret->registerModel<RandomNumberModel>("Operators");
ret->registerModel<LongProcessingRandomNumber>("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 @@ -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
29 changes: 15 additions & 14 deletions include/QtNodes/internal/Definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,21 @@ Q_NAMESPACE_EXPORT(NODE_EDITOR_PUBLIC)
/**
* 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 @@ -86,6 +86,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 Down Expand Up @@ -114,6 +118,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 @@ -189,6 +195,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 @@ -56,6 +56,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 @@ -381,4 +383,31 @@ void DefaultNodePainter::drawValidationIcon(QPainter *painter, NodeGraphicsObjec
pixmap);
}

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