mirror of
https://github.com/arabine/open-story-teller.git
synced 2025-12-07 01:15:14 +01:00
285 lines
9.8 KiB
C++
285 lines
9.8 KiB
C++
#include "DefaultNodePainter.hpp"
|
|
|
|
#include <cmath>
|
|
|
|
#include <QtCore/QMargins>
|
|
|
|
#include "AbstractGraphModel.hpp"
|
|
#include "AbstractNodeGeometry.hpp"
|
|
#include "BasicGraphicsScene.hpp"
|
|
#include "ConnectionGraphicsObject.hpp"
|
|
#include "ConnectionIdUtils.hpp"
|
|
#include "NodeGraphicsObject.hpp"
|
|
#include "NodeState.hpp"
|
|
#include "StyleCollection.hpp"
|
|
|
|
namespace QtNodes {
|
|
|
|
void DefaultNodePainter::paint(QPainter *painter, NodeGraphicsObject &ngo) const
|
|
{
|
|
// TODO?
|
|
//AbstractNodeGeometry & geometry = ngo.nodeScene()->nodeGeometry();
|
|
//geometry.recomputeSizeIfFontChanged(painter->font());
|
|
|
|
drawNodeRect(painter, ngo);
|
|
|
|
drawConnectionPoints(painter, ngo);
|
|
|
|
drawFilledConnectionPoints(painter, ngo);
|
|
|
|
drawNodeCaption(painter, ngo);
|
|
|
|
drawEntryLabels(painter, ngo);
|
|
|
|
drawResizeRect(painter, ngo);
|
|
}
|
|
|
|
void DefaultNodePainter::drawNodeRect(QPainter *painter, NodeGraphicsObject &ngo) const
|
|
{
|
|
AbstractGraphModel &model = ngo.graphModel();
|
|
|
|
NodeId const nodeId = ngo.nodeId();
|
|
|
|
AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
|
|
|
|
QSize size = geometry.size(nodeId);
|
|
|
|
QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
|
|
|
|
NodeStyle nodeStyle(json.object());
|
|
|
|
auto color = ngo.isSelected() ? nodeStyle.SelectedBoundaryColor : nodeStyle.NormalBoundaryColor;
|
|
|
|
// if (ngo.nodeState().hovered()) {
|
|
// QPen p(color, nodeStyle.HoveredPenWidth);
|
|
// painter->setPen(p);
|
|
// } else {
|
|
// QPen p(color, nodeStyle.PenWidth);
|
|
// painter->setPen(p);
|
|
// }
|
|
QPen pen = painter->pen();
|
|
pen.setBrush(color);
|
|
pen.setWidth(2);
|
|
painter->setPen(pen);
|
|
painter->setBrush(nodeStyle.GradientColor0);
|
|
|
|
QRectF boundary(0, 0, size.width(), size.height());
|
|
painter->drawRect(boundary);
|
|
}
|
|
|
|
void DefaultNodePainter::drawConnectionPoints(QPainter *painter, NodeGraphicsObject &ngo) const
|
|
{
|
|
AbstractGraphModel &model = ngo.graphModel();
|
|
NodeId const nodeId = ngo.nodeId();
|
|
AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
|
|
|
|
QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
|
|
NodeStyle nodeStyle(json.object());
|
|
|
|
auto const &connectionStyle = StyleCollection::connectionStyle();
|
|
|
|
float diameter = nodeStyle.ConnectionPointDiameter;
|
|
auto reducedDiameter = diameter * 0.6;
|
|
|
|
for (PortType portType : {PortType::Out, PortType::In}) {
|
|
size_t const n = model
|
|
.nodeData(nodeId,
|
|
(portType == PortType::Out) ? NodeRole::OutPortCount
|
|
: NodeRole::InPortCount)
|
|
.toUInt();
|
|
|
|
for (PortIndex portIndex = 0; portIndex < n; ++portIndex) {
|
|
QPointF p = geometry.portPosition(nodeId, portType, portIndex);
|
|
|
|
auto const &dataType = model.portData(nodeId, portType, portIndex, PortRole::DataType)
|
|
.value<NodeDataType>();
|
|
|
|
double r = 1.0;
|
|
|
|
NodeState const &state = ngo.nodeState();
|
|
|
|
if (auto const *cgo = state.connectionForReaction()) {
|
|
PortType requiredPort = cgo->connectionState().requiredPort();
|
|
|
|
if (requiredPort == portType) {
|
|
ConnectionId possibleConnectionId = makeCompleteConnectionId(cgo->connectionId(),
|
|
nodeId,
|
|
portIndex);
|
|
|
|
bool const possible = model.connectionPossible(possibleConnectionId);
|
|
|
|
auto cp = cgo->sceneTransform().map(cgo->endPoint(requiredPort));
|
|
cp = ngo.sceneTransform().inverted().map(cp);
|
|
|
|
auto diff = cp - p;
|
|
double dist = std::sqrt(QPointF::dotProduct(diff, diff));
|
|
|
|
if (possible) {
|
|
double const thres = 40.0;
|
|
r = (dist < thres) ? (2.0 - dist / thres) : 1.0;
|
|
} else {
|
|
double const thres = 80.0;
|
|
r = (dist < thres) ? (dist / thres) : 1.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (connectionStyle.useDataDefinedColors()) {
|
|
painter->setBrush(connectionStyle.normalColor(dataType.id));
|
|
} else {
|
|
painter->setBrush(nodeStyle.ConnectionPointColor);
|
|
}
|
|
|
|
painter->drawEllipse(p, reducedDiameter * r, reducedDiameter * r);
|
|
}
|
|
}
|
|
|
|
if (ngo.nodeState().connectionForReaction()) {
|
|
ngo.nodeState().resetConnectionForReaction();
|
|
}
|
|
}
|
|
|
|
void DefaultNodePainter::drawFilledConnectionPoints(QPainter *painter, NodeGraphicsObject &ngo) const
|
|
{
|
|
AbstractGraphModel &model = ngo.graphModel();
|
|
NodeId const nodeId = ngo.nodeId();
|
|
AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
|
|
|
|
QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
|
|
NodeStyle nodeStyle(json.object());
|
|
|
|
auto diameter = nodeStyle.ConnectionPointDiameter;
|
|
|
|
for (PortType portType : {PortType::Out, PortType::In}) {
|
|
size_t const n = model
|
|
.nodeData(nodeId,
|
|
(portType == PortType::Out) ? NodeRole::OutPortCount
|
|
: NodeRole::InPortCount)
|
|
.toUInt();
|
|
|
|
for (PortIndex portIndex = 0; portIndex < n; ++portIndex) {
|
|
QPointF p = geometry.portPosition(nodeId, portType, portIndex);
|
|
|
|
auto const &connected = model.connections(nodeId, portType, portIndex);
|
|
|
|
if (!connected.empty()) {
|
|
auto const &dataType = model
|
|
.portData(nodeId, portType, portIndex, PortRole::DataType)
|
|
.value<NodeDataType>();
|
|
|
|
auto const &connectionStyle = StyleCollection::connectionStyle();
|
|
if (connectionStyle.useDataDefinedColors()) {
|
|
QColor const c = connectionStyle.normalColor(dataType.id);
|
|
painter->setPen(c);
|
|
painter->setBrush(c);
|
|
} else {
|
|
painter->setPen(nodeStyle.FilledConnectionPointColor);
|
|
painter->setBrush(nodeStyle.FilledConnectionPointColor);
|
|
}
|
|
|
|
painter->drawEllipse(p, diameter * 0.4, diameter * 0.4);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DefaultNodePainter::drawNodeCaption(QPainter *painter, NodeGraphicsObject &ngo) const
|
|
{
|
|
AbstractGraphModel &model = ngo.graphModel();
|
|
NodeId const nodeId = ngo.nodeId();
|
|
AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
|
|
|
|
if (!model.nodeData(nodeId, NodeRole::CaptionVisible).toBool())
|
|
return;
|
|
|
|
QString const name = model.nodeData(nodeId, NodeRole::Caption).toString();
|
|
|
|
QFont f({ "Arial", 10 });
|
|
f.setBold(true);
|
|
|
|
QPointF position = geometry.captionPosition(nodeId);
|
|
|
|
QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
|
|
NodeStyle nodeStyle(json.object());
|
|
|
|
|
|
painter->setBrush(QBrush("#f7aa1b"));
|
|
QFontMetrics metrics(f);
|
|
auto fontRect = metrics.boundingRect(name);
|
|
|
|
QSize sizeH = geometry.size(nodeId);
|
|
QRectF titleRect;
|
|
|
|
int w = sizeH.width();
|
|
// titleRect.setX(2);
|
|
// titleRect.setY(2);
|
|
titleRect.setWidth(w);
|
|
titleRect.setHeight(fontRect.height() + position.ry());
|
|
QPen pen = painter->pen();
|
|
pen.setWidth(0);
|
|
painter->setPen(pen);
|
|
painter->drawRect(titleRect);
|
|
|
|
painter->setFont(f);
|
|
painter->setPen(Qt::black);
|
|
painter->drawText(position, name);
|
|
|
|
f.setBold(false);
|
|
painter->setFont(f);
|
|
}
|
|
|
|
void DefaultNodePainter::drawEntryLabels(QPainter *painter, NodeGraphicsObject &ngo) const
|
|
{
|
|
AbstractGraphModel &model = ngo.graphModel();
|
|
NodeId const nodeId = ngo.nodeId();
|
|
AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
|
|
|
|
QJsonDocument json = QJsonDocument::fromVariant(model.nodeData(nodeId, NodeRole::Style));
|
|
NodeStyle nodeStyle(json.object());
|
|
|
|
for (PortType portType : {PortType::Out, PortType::In}) {
|
|
unsigned int n = model.nodeData<unsigned int>(nodeId,
|
|
(portType == PortType::Out)
|
|
? NodeRole::OutPortCount
|
|
: NodeRole::InPortCount);
|
|
|
|
for (PortIndex portIndex = 0; portIndex < n; ++portIndex) {
|
|
auto const &connected = model.connections(nodeId, portType, portIndex);
|
|
|
|
QPointF p = geometry.portTextPosition(nodeId, portType, portIndex);
|
|
|
|
if (connected.empty())
|
|
painter->setPen(nodeStyle.FontColorFaded);
|
|
else
|
|
painter->setPen(nodeStyle.FontColor);
|
|
|
|
QString s;
|
|
|
|
if (model.portData<bool>(nodeId, portType, portIndex, PortRole::CaptionVisible)) {
|
|
s = model.portData<QString>(nodeId, portType, portIndex, PortRole::Caption);
|
|
} else {
|
|
auto portData = model.portData(nodeId, portType, portIndex, PortRole::DataType);
|
|
|
|
s = portData.value<NodeDataType>().name;
|
|
}
|
|
|
|
painter->drawText(p, s);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DefaultNodePainter::drawResizeRect(QPainter *painter, NodeGraphicsObject &ngo) const
|
|
{
|
|
AbstractGraphModel &model = ngo.graphModel();
|
|
NodeId const nodeId = ngo.nodeId();
|
|
AbstractNodeGeometry &geometry = ngo.nodeScene()->nodeGeometry();
|
|
|
|
if (model.nodeFlags(nodeId) & NodeFlag::Resizable) {
|
|
painter->setBrush(Qt::gray);
|
|
|
|
painter->drawEllipse(geometry.resizeHandleRect(nodeId));
|
|
}
|
|
}
|
|
|
|
} // namespace QtNodes
|