Files

420 lines
8.4 KiB
C++
Raw Permalink Normal View History

2015-12-13 21:42:10 +01:00
#include "NodeGeometry.hpp"
#include <iostream>
2016-10-06 12:06:10 +02:00
#include <cmath>
2020-02-18 09:32:41 +01:00
#include "Definitions.hpp"
#include "GraphModel.hpp"
//#include "NodeDataModel.hpp"
//#include "Node.hpp"
#include "NodeGraphicsObject.hpp"
2015-12-20 17:46:00 +01:00
2016-12-01 16:55:10 +01:00
#include "StyleCollection.hpp"
2017-01-30 10:31:43 +01:00
using QtNodes::NodeGeometry;
2017-01-30 15:09:49 +01:00
using QtNodes::NodeDataModel;
2017-01-30 10:31:43 +01:00
using QtNodes::PortIndex;
2017-01-30 15:09:49 +01:00
using QtNodes::PortType;
2020-02-07 00:16:39 +01:00
2015-12-13 21:42:10 +01:00
NodeGeometry::
2020-02-07 00:16:39 +01:00
NodeGeometry(NodeId nodeId, GraphModel const & graphModel)
: _nodeId(nodeId)
, _graphModel(graphModel)
, _defaultInPortWidth(70)
, _defaultOutPortWidth(70)
2015-12-13 21:42:10 +01:00
, _entryHeight(20)
2020-02-07 00:16:39 +01:00
, _verticalSpacing(20)
, _fontMetrics(QFont())
2016-12-22 13:17:40 +01:00
, _boldFontMetrics(QFont())
{
QFont f; f.setBold(true);
2017-01-30 10:31:43 +01:00
2016-12-22 13:17:40 +01:00
_boldFontMetrics = QFontMetrics(f);
2020-02-07 17:36:32 +01:00
_entryHeight = _fontMetrics.height();
2016-12-22 13:17:40 +01:00
}
2015-12-13 21:42:10 +01:00
2019-02-09 19:13:27 +01:00
2020-02-07 00:16:39 +01:00
QSize
2015-12-13 21:42:10 +01:00
NodeGeometry::
2020-02-07 00:16:39 +01:00
size() const
2015-12-13 21:42:10 +01:00
{
2020-02-07 17:36:32 +01:00
//return _graphModel.nodeData(_nodeId, NodeRole::Size);
return recalculateSize();
2015-12-13 21:42:10 +01:00
}
2020-02-07 17:36:32 +01:00
//void
//NodeGeometry::
//setSize(QSize s)
//{
//return _graphModel.setNodeData(_nodeId, NodeRole::Size, s);
//}
2020-02-07 00:16:39 +01:00
unsigned int
NodeGeometry::
entryHeight() const
{
return _entryHeight;
}
unsigned int
NodeGeometry::
verticalSpacing() const
{
return _verticalSpacing;
}
bool
NodeGeometry::
hovered() const
{
return _graphModel.nodeData(_nodeId, NodeRole::Hovered);
}
void
NodeGeometry::
setHovered(bool hovered)
{
return _graphModel.setNodeData(_nodeId, NodeRole::Size, hovered);
}
unsigned int
NodeGeometry::
nInPorts() const
{
return _graphModel.nodeData(_nodeId, NodeRole::NumberOfInPorts);
}
unsigned int
NodeGeometry::
nOutPorts() const
{
return _graphModel.nodeData(_nodeId, NodeRole::NumberOfOutPorts);
}
//QRectF
//NodeGeometry::
//entryBoundingRect() const
//{
//double const addon = 0.0;
//return QRectF(0 - addon,
//0 - addon,
//_entryWidth + 2 * addon,
//_entryHeight + 2 * addon);
//}
2015-12-13 21:42:10 +01:00
QRectF
NodeGeometry::
boundingRect() const
{
2020-02-07 00:16:39 +01:00
auto const & style = _graphModel.nodeData(_nodeId, NodeRole::Style);
auto const & nodeStyle = StyleCollection::nodeStyle();
2016-12-01 16:55:10 +01:00
double addon = 4 * nodeStyle.ConnectionPointDiameter;
2015-12-13 21:42:10 +01:00
2020-02-07 17:36:32 +01:00
QSize size = recalculateSize();
2015-12-13 21:42:10 +01:00
return QRectF(0 - addon,
0 - addon,
2020-02-07 17:36:32 +01:00
size.width() + 2 * addon,
size.height() + 2 * addon);
2015-12-13 21:42:10 +01:00
}
2020-02-07 17:36:32 +01:00
QSize
2015-12-13 21:42:10 +01:00
NodeGeometry::
recalculateSize() const
2015-12-13 21:42:10 +01:00
{
2020-02-07 17:36:32 +01:00
unsigned int height = 0;
{
2020-02-07 00:16:39 +01:00
unsigned int maxNumOfEntries = std::max(nInPorts(), nOutPorts());
unsigned int step = _entryHeight + _verticalSpacing;
2020-02-07 17:36:32 +01:00
height = step * maxNumOfEntries;
}
2015-12-20 22:49:55 +01:00
2020-02-07 00:16:39 +01:00
if (auto w = _graphModel.nodeData(_nodeId, NodeRole::Widget))
{
2020-02-07 17:36:32 +01:00
height = std::max(_height, static_cast<unsigned int>(w->height()));
}
2020-02-07 17:36:32 +01:00
height += captionHeight();
2016-08-22 22:20:34 +02:00
2020-02-07 17:36:32 +01:00
inPortWidth = portWidth(PortType::In);
outPortWidth = portWidth(PortType::Out);
2015-12-13 21:42:10 +01:00
2020-02-07 17:36:32 +01:00
unsigned int width = inPortWidth + outPortWidth + 2 * _spacing;
2016-05-30 16:37:11 +02:00
2020-02-07 17:36:32 +01:00
if (auto w = _graphModel.nodeData(_nodeId, NodeRole::Widget);
2016-05-30 16:37:11 +02:00
{
2020-02-07 17:36:32 +01:00
width += w->width();
2016-05-30 16:37:11 +02:00
}
2016-12-22 13:17:40 +01:00
2020-02-07 17:36:32 +01:00
width = std::max(width, captionWidth());
2020-02-07 17:36:32 +01:00
return QSize(width, height);
}
2020-02-07 17:36:32 +01:00
QSize
NodeGeometry::
2016-12-22 13:17:40 +01:00
recalculateSize(QFont const & font) const
{
2016-12-22 13:17:40 +01:00
QFontMetrics fontMetrics(font);
QFont boldFont = font;
2017-01-30 10:31:43 +01:00
2016-12-22 13:17:40 +01:00
boldFont.setBold(true);
QFontMetrics boldFontMetrics(boldFont);
if (_boldFontMetrics != boldFontMetrics)
{
2017-01-30 10:31:43 +01:00
_fontMetrics = fontMetrics;
2016-12-22 13:17:40 +01:00
_boldFontMetrics = boldFontMetrics;
}
2020-02-07 17:36:32 +01:00
return recalculateSize();
2015-12-13 21:42:10 +01:00
}
QPointF
NodeGeometry::
portScenePosition(PortIndex index,
2020-02-07 00:16:39 +01:00
PortType portType,
QTransform const & t) const
2015-12-13 21:42:10 +01:00
{
2020-02-07 00:16:39 +01:00
auto const & nodeStyle = StyleCollection::nodeStyle();
2016-12-01 16:55:10 +01:00
2015-12-13 21:42:10 +01:00
unsigned int step = _entryHeight + _spacing;
2015-12-20 17:46:00 +01:00
QPointF result;
2016-08-22 22:20:34 +02:00
double totalHeight = 0.0;
2016-12-22 13:17:40 +01:00
totalHeight += captionHeight();
2016-08-22 22:20:34 +02:00
totalHeight += step * index;
// TODO: why?
totalHeight += step / 2.0;
2016-04-20 23:18:10 +02:00
switch (portType)
2015-12-13 21:42:10 +01:00
{
case PortType::Out:
2015-12-13 21:42:10 +01:00
{
double x = _width + nodeStyle.ConnectionPointDiameter;
2015-12-13 21:42:10 +01:00
2015-12-20 17:46:00 +01:00
result = QPointF(x, totalHeight);
2015-12-13 21:42:10 +01:00
break;
}
case PortType::In:
2015-12-13 21:42:10 +01:00
{
double x = 0.0 - nodeStyle.ConnectionPointDiameter;
2015-12-13 21:42:10 +01:00
2015-12-20 17:46:00 +01:00
result = QPointF(x, totalHeight);
2015-12-13 21:42:10 +01:00
break;
}
default:
break;
}
2015-12-20 17:46:00 +01:00
return t.map(result);
2015-12-13 21:42:10 +01:00
}
2015-12-13 22:39:37 +01:00
2016-04-20 23:18:10 +02:00
PortIndex
2015-12-20 17:46:00 +01:00
NodeGeometry::
2016-04-20 23:18:10 +02:00
checkHitScenePoint(PortType portType,
2016-04-15 22:40:45 +02:00
QPointF const scenePoint,
QTransform const & sceneTransform) const
2015-12-20 17:46:00 +01:00
{
2020-02-07 00:16:39 +01:00
auto const & nodeStyle = StyleCollection::nodeStyle();
2016-12-01 16:55:10 +01:00
2016-04-20 23:18:10 +02:00
PortIndex result = INVALID;
2015-12-20 17:46:00 +01:00
if (portType == PortType::None)
2015-12-20 17:46:00 +01:00
return result;
double const tolerance = 2.0 * nodeStyle.ConnectionPointDiameter;
2015-12-20 17:46:00 +01:00
unsigned int const nItems = _dataModel->nPorts(portType);
2015-12-20 17:46:00 +01:00
for (unsigned int i = 0; i < nItems; ++i)
2015-12-20 17:46:00 +01:00
{
auto pp = portScenePosition(i, portType, sceneTransform);
2020-02-07 00:16:39 +01:00
QPointF p = pp - scenePoint;
auto distance = std::sqrt(QPointF::dotProduct(p, p));
2015-12-20 17:46:00 +01:00
if (distance < tolerance)
{
2016-04-20 23:18:10 +02:00
result = PortIndex(i);
2015-12-20 17:46:00 +01:00
break;
}
}
return result;
}
2016-05-31 22:55:28 +02:00
2016-09-18 15:05:14 +02:00
QRect
NodeGeometry::
resizeRect() const
{
unsigned int rectSize = 7;
return QRect(_width - rectSize,
_height - rectSize,
rectSize,
rectSize);
}
2016-05-31 22:55:28 +02:00
QPointF
NodeGeometry::
widgetPosition() const
{
if (auto w = _dataModel->embeddedWidget())
{
2019-07-28 13:41:55 +01:00
if (w->sizePolicy().verticalPolicy() & QSizePolicy::ExpandFlag)
{
2019-07-28 13:41:55 +01:00
// If the widget wants to use as much vertical space as possible, place it immediately after the caption.
return QPointF(_spacing + portWidth(PortType::In), captionHeight());
}
2019-07-28 13:41:55 +01:00
else
{
if (_dataModel->validationState() != NodeValidationState::Valid)
{
return QPointF(_spacing + portWidth(PortType::In),
2020-02-07 00:16:39 +01:00
(captionHeight() + _height - validationHeight() - _spacing - w->height()) / 2.0);
2019-07-28 13:41:55 +01:00
}
2017-01-30 10:31:43 +01:00
2020-02-07 00:16:39 +01:00
return QPointF(_spacing + portWidth(PortType::In),
(captionHeight() + _height - w->height()) / 2.0);
2019-07-28 13:41:55 +01:00
}
2016-05-31 22:55:28 +02:00
}
return QPointF();
}
2020-02-07 00:16:39 +01:00
2019-07-28 13:41:55 +01:00
int
NodeGeometry::
equivalentWidgetHeight() const
{
if (_dataModel->validationState() != NodeValidationState::Valid)
{
return height() - captionHeight() + validationHeight();
}
return height() - captionHeight();
}
2016-05-31 22:55:28 +02:00
2020-02-07 00:16:39 +01:00
2016-08-22 22:20:34 +02:00
unsigned int
NodeGeometry::
2016-12-22 13:17:40 +01:00
captionHeight() const
2016-08-22 22:20:34 +02:00
{
2020-02-07 00:16:39 +01:00
if (!_graphModel.nodeData(_nodeId, NodeRole::CaptionVisible))
2016-08-22 22:20:34 +02:00
return 0;
2020-02-07 00:16:39 +01:00
QString name = _graphModel.nodeData(_nodeId, NodeRole::Caption);
2016-09-23 09:45:07 +02:00
2016-12-22 13:17:40 +01:00
return _boldFontMetrics.boundingRect(name).height();
}
unsigned int
NodeGeometry::
captionWidth() const
{
if (!_dataModel->captionVisible())
return 0;
QString name = _dataModel->caption();
return _boldFontMetrics.boundingRect(name).width();
2016-08-22 22:20:34 +02:00
}
unsigned int
NodeGeometry::
validationHeight() const
{
QString msg = _dataModel->validationMessage();
return _boldFontMetrics.boundingRect(msg).height();
}
unsigned int
NodeGeometry::
validationWidth() const
{
QString msg = _dataModel->validationMessage();
return _boldFontMetrics.boundingRect(msg).width();
}
2020-02-18 09:32:41 +01:00
//QPointF
//NodeGeometry::
//calculateNodePositionBetweenNodePorts(PortIndex targetPortIndex, PortType targetPort, Node * targetNode,
//PortIndex sourcePortIndex, PortType sourcePort, Node * sourceNode,
//Node & newNode)
//{
////Calculating the nodes position in the scene. It'll be positioned half way
////between the two ports that it "connects". The first line calculates the
////halfway point between the ports (node position + port position on the node
////for both nodes averaged). The second line offsets this coordinate with the
////size of the new node, so that the new nodes center falls on the originally
////calculated coordinate, instead of it's upper left corner.
//auto converterNodePos = (sourceNode->nodeGraphicsObject().pos() + sourceNode->nodeGeometry().portScenePosition(sourcePortIndex, sourcePort) +
//targetNode->nodeGraphicsObject().pos() + targetNode->nodeGeometry().portScenePosition(targetPortIndex, targetPort)) / 2.0f;
//converterNodePos.setX(converterNodePos.x() - newNode.nodeGeometry().width() / 2.0f);
//converterNodePos.setY(converterNodePos.y() - newNode.nodeGeometry().height() / 2.0f);
//return converterNodePos;
//}
2016-05-31 22:55:28 +02:00
unsigned int
NodeGeometry::
portWidth(PortType portType) const
{
unsigned width = 0;
2016-06-05 22:16:43 +02:00
for (auto i = 0ul; i < _dataModel->nPorts(portType); ++i)
2016-05-31 22:55:28 +02:00
{
QString name;
2017-01-30 10:31:43 +01:00
if (_dataModel->portCaptionVisible(portType, i))
{
name = _dataModel->portCaption(portType, i);
}
else
{
name = _dataModel->dataType(portType, i).name;
}
2016-05-31 22:55:28 +02:00
width = std::max(unsigned(_fontMetrics.width(name)),
width);
}
return width;
}