You've already forked nodeeditor
mirror of
https://github.com/AxioDL/nodeeditor.git
synced 2026-03-30 11:48:31 -07:00
a62f088b2b
* Add option to set custom captions for node ports * Calculator example modified to consistently use custom ports labels where it makes sense * Minor fixes in modified code
272 lines
4.9 KiB
C++
272 lines
4.9 KiB
C++
#include "NodeGeometry.hpp"
|
|
|
|
#include <iostream>
|
|
#include <cmath>
|
|
|
|
#include "PortType.hpp"
|
|
#include "NodeState.hpp"
|
|
#include "NodeDataModel.hpp"
|
|
|
|
#include "StyleCollection.hpp"
|
|
|
|
NodeGeometry::
|
|
NodeGeometry(std::unique_ptr<NodeDataModel> const &dataModel)
|
|
: _width(100)
|
|
, _height(150)
|
|
, _inputPortWidth(70)
|
|
, _outputPortWidth(70)
|
|
, _entryHeight(20)
|
|
, _spacing(20)
|
|
, _hovered(false)
|
|
, _nSources(dataModel->nPorts(PortType::Out))
|
|
, _nSinks(dataModel->nPorts(PortType::In))
|
|
, _draggingPos(-1000, -1000)
|
|
, _dataModel(dataModel)
|
|
, _fontMetrics(QFont())
|
|
, _boldFontMetrics(QFont())
|
|
{
|
|
QFont f; f.setBold(true);
|
|
_boldFontMetrics = QFontMetrics(f);
|
|
}
|
|
|
|
QRectF
|
|
NodeGeometry::
|
|
entryBoundingRect() const
|
|
{
|
|
double const addon = 0.0;
|
|
|
|
return QRectF(0 - addon,
|
|
0 - addon,
|
|
_entryWidth + 2 * addon,
|
|
_entryHeight + 2 * addon);
|
|
}
|
|
|
|
|
|
QRectF
|
|
NodeGeometry::
|
|
boundingRect() const
|
|
{
|
|
auto const &nodeStyle = StyleCollection::nodeStyle();
|
|
|
|
double addon = 4 * nodeStyle.ConnectionPointDiameter;
|
|
|
|
return QRectF(0 - addon,
|
|
0 - addon,
|
|
_width + 2 * addon,
|
|
_height + 2 * addon);
|
|
}
|
|
|
|
|
|
void
|
|
NodeGeometry::
|
|
recalculateSize() const
|
|
{
|
|
_entryHeight = _fontMetrics.height();
|
|
|
|
{
|
|
unsigned int maxNumOfEntries = std::max(_nSinks, _nSources);
|
|
unsigned int step = _entryHeight + _spacing;
|
|
_height = step * maxNumOfEntries;
|
|
}
|
|
|
|
if (auto w = _dataModel->embeddedWidget())
|
|
{
|
|
_height = std::max(_height, static_cast<unsigned>(w->height()));
|
|
}
|
|
|
|
_height += captionHeight();
|
|
|
|
_inputPortWidth = portWidth(PortType::In);
|
|
_outputPortWidth = portWidth(PortType::Out);
|
|
|
|
_width = _inputPortWidth +
|
|
_outputPortWidth +
|
|
2 * _spacing;
|
|
|
|
if (auto w = _dataModel->embeddedWidget())
|
|
{
|
|
_width += w->width();
|
|
}
|
|
|
|
_width = std::max(_width, captionWidth());
|
|
}
|
|
|
|
|
|
void
|
|
NodeGeometry::
|
|
recalculateSize(QFont const & font) const
|
|
{
|
|
QFontMetrics fontMetrics(font);
|
|
QFont boldFont = font;
|
|
boldFont.setBold(true);
|
|
|
|
QFontMetrics boldFontMetrics(boldFont);
|
|
|
|
if (_boldFontMetrics != boldFontMetrics)
|
|
{
|
|
_fontMetrics = fontMetrics;
|
|
_boldFontMetrics = boldFontMetrics;
|
|
|
|
recalculateSize();
|
|
}
|
|
}
|
|
|
|
|
|
QPointF
|
|
NodeGeometry::
|
|
portScenePosition(int index,
|
|
PortType portType,
|
|
QTransform t) const
|
|
{
|
|
auto const &nodeStyle = StyleCollection::nodeStyle();
|
|
|
|
unsigned int step = _entryHeight + _spacing;
|
|
|
|
QPointF result;
|
|
|
|
double totalHeight = 0.0;
|
|
|
|
totalHeight += captionHeight();
|
|
|
|
totalHeight += step * index;
|
|
|
|
// TODO: why?
|
|
totalHeight += step / 2.0;
|
|
|
|
switch (portType)
|
|
{
|
|
case PortType::Out:
|
|
{
|
|
double x = _width + nodeStyle.ConnectionPointDiameter;
|
|
|
|
result = QPointF(x, totalHeight);
|
|
break;
|
|
}
|
|
|
|
case PortType::In:
|
|
{
|
|
double x = 0.0 - nodeStyle.ConnectionPointDiameter;
|
|
|
|
result = QPointF(x, totalHeight);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return t.map(result);
|
|
}
|
|
|
|
|
|
PortIndex
|
|
NodeGeometry::
|
|
checkHitScenePoint(PortType portType,
|
|
QPointF const scenePoint,
|
|
QTransform sceneTransform) const
|
|
{
|
|
auto const &nodeStyle = StyleCollection::nodeStyle();
|
|
|
|
PortIndex result = INVALID;
|
|
|
|
if (portType == PortType::None)
|
|
return result;
|
|
|
|
double const tolerance = 2.0 * nodeStyle.ConnectionPointDiameter;
|
|
|
|
size_t const nItems = _dataModel->nPorts(portType);
|
|
|
|
for (size_t i = 0; i < nItems; ++i)
|
|
{
|
|
auto pp = portScenePosition(i, portType, sceneTransform);
|
|
|
|
QPointF p = pp - scenePoint;
|
|
auto distance = std::sqrt(QPointF::dotProduct(p, p));
|
|
|
|
if (distance < tolerance)
|
|
{
|
|
result = PortIndex(i);
|
|
break;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
|
|
QRect
|
|
NodeGeometry::
|
|
resizeRect() const
|
|
{
|
|
unsigned int rectSize = 7;
|
|
|
|
return QRect(_width - rectSize,
|
|
_height - rectSize,
|
|
rectSize,
|
|
rectSize);
|
|
}
|
|
|
|
|
|
QPointF
|
|
NodeGeometry::
|
|
widgetPosition() const
|
|
{
|
|
if (auto w = _dataModel->embeddedWidget())
|
|
{
|
|
|
|
return QPointF(_spacing + portWidth(PortType::In),
|
|
(captionHeight() + _height - w->height()) / 2.0);
|
|
}
|
|
|
|
return QPointF();
|
|
}
|
|
|
|
|
|
unsigned int
|
|
NodeGeometry::
|
|
captionHeight() const
|
|
{
|
|
if (!_dataModel->captionVisible())
|
|
return 0;
|
|
|
|
QString name = _dataModel->caption();
|
|
|
|
return _boldFontMetrics.boundingRect(name).height();
|
|
}
|
|
|
|
|
|
unsigned int
|
|
NodeGeometry::
|
|
captionWidth() const
|
|
{
|
|
if (!_dataModel->captionVisible())
|
|
return 0;
|
|
|
|
QString name = _dataModel->caption();
|
|
|
|
return _boldFontMetrics.boundingRect(name).width();
|
|
}
|
|
|
|
|
|
unsigned int
|
|
NodeGeometry::
|
|
portWidth(PortType portType) const
|
|
{
|
|
unsigned width = 0;
|
|
|
|
for (auto i = 0ul; i < _dataModel->nPorts(portType); ++i)
|
|
{
|
|
QString name;
|
|
|
|
if (_dataModel->portCaptionVisible(portType, i))
|
|
name = _dataModel->portCaption(portType, i);
|
|
else
|
|
name = _dataModel->dataType(portType, i).name;
|
|
|
|
width = std::max(unsigned(_fontMetrics.width(name)),
|
|
width);
|
|
}
|
|
|
|
return width;
|
|
}
|