Files

419 lines
10 KiB
C++
Raw Permalink Normal View History

2015-12-13 21:42:10 +01:00
#include "NodePainter.hpp"
2016-10-06 12:06:10 +02:00
#include <cmath>
2015-12-20 17:46:00 +01:00
#include <QtCore/QMargins>
2020-02-07 17:36:32 +01:00
#include "GraphicsScene.hpp"
2020-02-07 00:16:39 +01:00
#include "Node.hpp"
#include "NodeDataModel.hpp"
#include "NodeGeometry.hpp"
#include "NodeGraphicsObject.hpp"
#include "NodeState.hpp"
#include "PortType.hpp"
#include "StyleCollection.hpp"
2015-12-13 21:42:10 +01:00
2020-02-07 17:36:32 +01:00
using QtNodes::GraphicsScene;
2020-02-07 00:16:39 +01:00
using QtNodes::GraphModel;
using QtNodes::Node;
2017-01-30 15:09:49 +01:00
using QtNodes::NodeGeometry;
using QtNodes::NodeGraphicsObject;
2020-02-07 00:16:39 +01:00
using QtNodes::NodePainter;
2017-01-30 15:09:49 +01:00
using QtNodes::NodeState;
2017-01-30 10:31:43 +01:00
2015-12-13 21:42:10 +01:00
void
NodePainter::
2020-02-07 00:16:39 +01:00
paint(QPainter * painter,
2020-02-07 17:36:32 +01:00
NodeId nodeId,
GraphicsScene const & scene)
2015-12-13 21:42:10 +01:00
{
2020-02-07 17:36:32 +01:00
NodeGeometry geom(nodeId, scene.graphModel());
2016-04-18 01:43:07 +02:00
2020-02-07 00:16:39 +01:00
NodeState const & state = node.nodeState();
NodeGraphicsObject const & graphicsObject = node.nodeGraphicsObject();
2016-09-20 15:22:05 +01:00
2016-12-22 13:17:40 +01:00
geom.recalculateSize(painter->font());
//--------------------------------------------
2020-02-07 00:16:39 +01:00
GraphModel const & graphModel = scene.graphModel();
2016-04-18 01:43:07 +02:00
2020-02-07 00:16:39 +01:00
drawNodeRect(painter, geom, graphModel, graphicsObject);
drawConnectionPoints(painter, geom, state, model, scene);
2015-12-21 22:55:50 +01:00
2016-12-01 16:55:10 +01:00
drawFilledConnectionPoints(painter, geom, state, model);
2015-12-21 22:55:50 +01:00
2016-08-22 22:20:34 +02:00
drawModelName(painter, geom, state, model);
2016-04-18 01:43:07 +02:00
drawEntryLabels(painter, geom, state, model);
2016-09-18 15:05:14 +02:00
drawResizeRect(painter, geom, model);
drawValidationRect(painter, geom, model, graphicsObject);
/// call custom painter
if (auto painterDelegate = model->painterDelegate())
{
painterDelegate->paint(painter, geom, model);
}
2015-12-21 22:55:50 +01:00
}
void
NodePainter::
2020-02-07 00:16:39 +01:00
drawNodeRect(QPainter * painter,
NodeGeometry const & geom,
NodeDataModel const * model,
2016-11-28 21:23:31 +01:00
NodeGraphicsObject const & graphicsObject)
2015-12-21 22:55:50 +01:00
{
2020-02-07 00:16:39 +01:00
NodeStyle const & nodeStyle = model->nodeStyle();
2016-12-01 16:55:10 +01:00
2020-02-07 17:36:32 +01:00
auto color = graphicsObject.isSelected() ?
nodeStyle.SelectedBoundaryColor :
nodeStyle.NormalBoundaryColor;
2016-09-20 15:22:05 +01:00
2015-12-13 21:42:10 +01:00
if (geom.hovered())
{
QPen p(color, nodeStyle.HoveredPenWidth);
2015-12-13 21:42:10 +01:00
painter->setPen(p);
}
else
{
QPen p(color, nodeStyle.PenWidth);
2015-12-13 21:42:10 +01:00
painter->setPen(p);
}
2015-12-20 19:00:28 +01:00
QLinearGradient gradient(QPointF(0.0, 0.0),
2015-12-21 21:10:25 +01:00
QPointF(2.0, geom.height()));
2015-12-20 19:00:28 +01:00
2020-02-07 00:16:39 +01:00
gradient.setColorAt(0.0, nodeStyle.GradientColor0);
gradient.setColorAt(0.03, nodeStyle.GradientColor1);
gradient.setColorAt(0.97, nodeStyle.GradientColor2);
2020-02-07 00:16:39 +01:00
gradient.setColorAt(1.0, nodeStyle.GradientColor3);
2015-12-20 19:00:28 +01:00
painter->setBrush(gradient);
2015-12-13 21:42:10 +01:00
float diam = nodeStyle.ConnectionPointDiameter;
2016-09-18 15:05:14 +02:00
2020-02-07 17:36:32 +01:00
QRectF boundary(-diam, -diam,
2.0 * diam + geom.width(),
2.0 * diam + geom.height());
2015-12-13 21:42:10 +01:00
double const radius = 3.0;
painter->drawRoundedRect(boundary, radius, radius);
2015-12-21 22:55:50 +01:00
}
2015-12-13 21:42:10 +01:00
void
NodePainter::
2020-02-07 00:16:39 +01:00
drawConnectionPoints(QPainter * painter,
NodeGeometry const & geom,
NodeState const & state,
2017-04-24 21:57:21 +02:00
NodeDataModel const * model,
2020-02-07 17:36:32 +01:00
GraphicsScene const & scene)
2015-12-13 21:42:10 +01:00
{
2020-02-07 00:16:39 +01:00
NodeStyle const & nodeStyle = model->nodeStyle();
auto const & connectionStyle = StyleCollection::connectionStyle();
2015-12-13 21:42:10 +01:00
2020-02-07 00:16:39 +01:00
float diameter = nodeStyle.ConnectionPointDiameter;
auto reducedDiameter = diameter * 0.6;
2015-12-13 21:42:10 +01:00
2020-02-07 00:16:39 +01:00
for (PortType portType: {PortType::Out, PortType::In})
2018-06-06 11:30:40 +02:00
{
size_t n = state.getEntries(portType).size();
for (unsigned int i = 0; i < n; ++i)
2015-12-20 22:49:55 +01:00
{
2018-06-06 11:30:40 +02:00
QPointF p = geom.portScenePosition(i, portType);
2015-12-13 22:39:37 +01:00
2018-06-06 11:30:40 +02:00
auto const & dataType = model->dataType(portType, i);
bool canConnect = (state.getEntries(portType)[i].empty() ||
(portType == PortType::Out &&
model->portOutConnectionPolicy(i) == NodeDataModel::ConnectionPolicy::Many) );
double r = 1.0;
if (state.isReacting() &&
canConnect &&
portType == state.reactingPortType())
2015-12-20 22:49:55 +01:00
{
2015-12-13 22:39:37 +01:00
2020-02-07 17:36:32 +01:00
auto diff = geom.draggingPos() - p;
double dist = std::sqrt(QPointF::dotProduct(diff, diff));
2020-02-07 00:16:39 +01:00
bool typeConvertable = false;
2017-04-24 21:57:21 +02:00
{
2018-06-06 11:30:40 +02:00
if (portType == PortType::In)
{
2018-06-06 11:30:40 +02:00
typeConvertable = scene.registry().getTypeConverter(state.reactingDataType(), dataType) != nullptr;
}
else
{
2018-06-06 11:30:40 +02:00
typeConvertable = scene.registry().getTypeConverter(dataType, state.reactingDataType()) != nullptr;
}
}
2018-06-06 11:30:40 +02:00
if (state.reactingDataType().id == dataType.id || typeConvertable)
{
2018-06-06 11:30:40 +02:00
double const thres = 40.0;
r = (dist < thres) ?
2020-02-07 00:16:39 +01:00
(2.0 - dist / thres ) :
1.0;
}
else
{
2018-06-06 11:30:40 +02:00
double const thres = 80.0;
r = (dist < thres) ?
2020-02-07 00:16:39 +01:00
(dist / thres) :
1.0;
}
2016-12-01 16:55:10 +01:00
}
2015-12-13 21:42:10 +01:00
2018-06-06 11:30:40 +02:00
if (connectionStyle.useDataDefinedColors())
{
painter->setBrush(connectionStyle.normalColor(dataType.id));
}
else
{
painter->setBrush(nodeStyle.ConnectionPointColor);
}
painter->drawEllipse(p,
reducedDiameter * r,
reducedDiameter * r);
}
2020-02-07 00:16:39 +01:00
}
;
2015-12-13 21:42:10 +01:00
}
void
NodePainter::
drawFilledConnectionPoints(QPainter * painter,
2020-02-07 00:16:39 +01:00
NodeGeometry const & geom,
NodeState const & state,
2017-04-24 21:57:21 +02:00
NodeDataModel const * model)
2015-12-13 21:42:10 +01:00
{
2020-02-07 00:16:39 +01:00
NodeStyle const & nodeStyle = model->nodeStyle();
2016-12-01 16:55:10 +01:00
auto const & connectionStyle = StyleCollection::connectionStyle();
2015-12-13 21:42:10 +01:00
auto diameter = nodeStyle.ConnectionPointDiameter;
2015-12-13 21:42:10 +01:00
2020-02-07 00:16:39 +01:00
for (PortType portType: {PortType::Out, PortType::In})
2018-06-06 11:30:40 +02:00
{
size_t n = state.getEntries(portType).size();
for (size_t i = 0; i < n; ++i)
2015-12-13 21:42:10 +01:00
{
2018-06-06 11:30:40 +02:00
QPointF p = geom.portScenePosition(i, portType);
2015-12-13 21:42:10 +01:00
2018-06-06 11:30:40 +02:00
if (!state.getEntries(portType)[i].empty())
2015-12-20 22:49:55 +01:00
{
2018-06-06 11:30:40 +02:00
auto const & dataType = model->dataType(portType, i);
2016-12-01 16:55:10 +01:00
2018-06-06 11:30:40 +02:00
if (connectionStyle.useDataDefinedColors())
2016-12-01 16:55:10 +01:00
{
2018-06-06 11:30:40 +02:00
QColor const c = connectionStyle.normalColor(dataType.id);
painter->setPen(c);
painter->setBrush(c);
}
else
{
painter->setPen(nodeStyle.FilledConnectionPointColor);
painter->setBrush(nodeStyle.FilledConnectionPointColor);
2017-04-24 21:57:21 +02:00
}
2015-12-13 21:42:10 +01:00
2018-06-06 11:30:40 +02:00
painter->drawEllipse(p,
diameter * 0.4,
diameter * 0.4);
}
}
}
2015-12-13 21:42:10 +01:00
}
2016-04-18 01:43:07 +02:00
2016-08-22 22:20:34 +02:00
void
NodePainter::
drawModelName(QPainter * painter,
2020-02-07 00:16:39 +01:00
NodeGeometry const & geom,
NodeState const & state,
2017-04-24 21:57:21 +02:00
NodeDataModel const * model)
2016-08-22 22:20:34 +02:00
{
2020-02-07 00:16:39 +01:00
NodeStyle const & nodeStyle = model->nodeStyle();
2016-12-01 16:55:10 +01:00
2016-08-22 22:20:34 +02:00
Q_UNUSED(state);
2016-09-23 09:45:07 +02:00
if (!model->captionVisible())
2016-08-22 22:20:34 +02:00
return;
2020-02-07 00:16:39 +01:00
QString const & name = model->caption();
2016-09-23 09:45:07 +02:00
2016-08-22 22:20:34 +02:00
QFont f = painter->font();
f.setBold(true);
QFontMetrics metrics(f);
auto rect = metrics.boundingRect(name);
QPointF position((geom.width() - rect.width()) / 2.0,
(geom.spacing() + geom.entryHeight()) / 3.0);
painter->setFont(f);
painter->setPen(nodeStyle.FontColor);
2016-08-22 22:20:34 +02:00
painter->drawText(position, name);
f.setBold(false);
painter->setFont(f);
}
2016-04-18 01:43:07 +02:00
void
NodePainter::
drawEntryLabels(QPainter * painter,
2020-02-07 00:16:39 +01:00
NodeGeometry const & geom,
NodeState const & state,
2017-04-24 21:57:21 +02:00
NodeDataModel const * model)
2016-04-18 01:43:07 +02:00
{
QFontMetrics const & metrics =
painter->fontMetrics();
2020-02-07 00:16:39 +01:00
for (PortType portType: {PortType::Out, PortType::In})
2018-06-06 11:30:40 +02:00
{
2020-02-07 00:16:39 +01:00
auto const & nodeStyle = model->nodeStyle();
2018-06-06 11:30:40 +02:00
2020-02-07 00:16:39 +01:00
auto & entries = state.getEntries(portType);
2018-06-06 11:30:40 +02:00
size_t n = entries.size();
for (size_t i = 0; i < n; ++i)
2016-04-18 01:43:07 +02:00
{
2018-06-06 11:30:40 +02:00
QPointF p = geom.portScenePosition(i, portType);
2016-04-18 01:43:07 +02:00
2018-06-06 11:30:40 +02:00
if (entries[i].empty())
painter->setPen(nodeStyle.FontColorFaded);
else
painter->setPen(nodeStyle.FontColor);
2016-08-22 22:20:34 +02:00
2018-06-06 11:30:40 +02:00
QString s;
2018-06-06 11:30:40 +02:00
if (model->portCaptionVisible(portType, i))
{
2018-06-06 11:30:40 +02:00
s = model->portCaption(portType, i);
}
else
{
s = model->dataType(portType, i).name;
}
2016-04-18 01:43:07 +02:00
2018-06-06 11:30:40 +02:00
auto rect = metrics.boundingRect(s);
2016-08-22 22:20:34 +02:00
2018-06-06 11:30:40 +02:00
p.setY(p.y() + rect.height() / 4.0);
switch (portType)
{
2020-02-07 00:16:39 +01:00
case PortType::In:
p.setX(5.0);
break;
2018-06-06 11:30:40 +02:00
2020-02-07 00:16:39 +01:00
case PortType::Out:
p.setX(geom.width() - 5.0 - rect.width());
break;
2018-06-06 11:30:40 +02:00
2020-02-07 00:16:39 +01:00
default:
break;
2018-06-06 11:30:40 +02:00
}
painter->drawText(p, s);
}
}
2016-04-18 01:43:07 +02:00
}
2016-09-18 15:05:14 +02:00
void
NodePainter::
drawResizeRect(QPainter * painter,
NodeGeometry const & geom,
2017-04-24 21:57:21 +02:00
NodeDataModel const * model)
2016-09-18 15:05:14 +02:00
{
if (model->resizable())
{
painter->setBrush(Qt::gray);
painter->drawEllipse(geom.resizeRect());
}
}
2017-04-24 21:57:21 +02:00
void
NodePainter::
drawValidationRect(QPainter * painter,
2020-02-07 00:16:39 +01:00
NodeGeometry const & geom,
2017-04-24 21:57:21 +02:00
NodeDataModel const * model,
NodeGraphicsObject const & graphicsObject)
{
auto modelValidationState = model->validationState();
2017-04-24 21:57:21 +02:00
if (modelValidationState != NodeValidationState::Valid)
{
2020-02-07 00:16:39 +01:00
NodeStyle const & nodeStyle = model->nodeStyle();
auto color = graphicsObject.isSelected()
2017-04-24 21:57:21 +02:00
? nodeStyle.SelectedBoundaryColor
: nodeStyle.NormalBoundaryColor;
if (geom.hovered())
{
QPen p(color, nodeStyle.HoveredPenWidth);
painter->setPen(p);
}
else
{
QPen p(color, nodeStyle.PenWidth);
painter->setPen(p);
}
//Drawing the validation message background
if (modelValidationState == NodeValidationState::Error)
{
painter->setBrush(nodeStyle.ErrorColor);
}
else
{
painter->setBrush(nodeStyle.WarningColor);
}
double const radius = 3.0;
2017-04-24 21:57:21 +02:00
float diam = nodeStyle.ConnectionPointDiameter;
2017-04-24 21:57:21 +02:00
QRectF boundary(-diam,
-diam + geom.height() - geom.validationHeight(),
2.0 * diam + geom.width(),
2.0 * diam + geom.validationHeight());
painter->drawRoundedRect(boundary, radius, radius);
painter->setBrush(Qt::gray);
//Drawing the validation message itself
2020-02-07 00:16:39 +01:00
QString const & errorMsg = model->validationMessage();
QFont f = painter->font();
2017-04-24 21:57:21 +02:00
QFontMetrics metrics(f);
auto rect = metrics.boundingRect(errorMsg);
QPointF position((geom.width() - rect.width()) / 2.0,
2017-04-24 21:57:21 +02:00
geom.height() - (geom.validationHeight() - diam) / 2.0);
painter->setFont(f);
painter->setPen(nodeStyle.FontColor);
painter->drawText(position, errorMsg);
}
2017-01-30 10:31:43 +01:00
}
2020-02-07 17:36:32 +01:00