Files
nodeeditor/src/NodeGeometry.cpp
T
David Bachrati a62f088b2b Renamable input and output ports on nodes (#45)
* 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
2017-01-12 23:10:03 +01:00

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;
}