Files
Enzo/src/gui/network/NodeGraphic.cpp
2025-06-26 09:00:46 +01:00

229 lines
6.8 KiB
C++

#include "gui/network/NodeGraphic.h"
#include <QTextDocument>
#include <iostream>
#include <qgraphicsitem.h>
#include <qnamespace.h>
#include <stdexcept>
#include <string>
#include "gui/network/DisplayFlagButton.h"
#include "gui/network/SocketGraphic.h"
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsSvgItem>
#include "gui/network/NodeIconGraphic.h"
NodeGraphic::NodeGraphic(QGraphicsItem *parent)
: QGraphicsItem(parent)
{
socketSize_ = 3;
titlePadding_=1;
titleText_ = "Attr_Del_1";
subTitleText_ = "Attribute Delete";
constexpr int height = 27;
constexpr int width = 100;
bodyRect_ = QRect(-width*0.5f, -height*0.5f, width, height);
iconScale_=height*0.55;
setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable);
initFonts();
initIcon();
initSockets();
initFlagButtons();
}
void NodeGraphic::initFonts()
{
// declare fonts
titleFont_ = QFont();
titleFont_.setPixelSize(8);
subTitleFont_ = QFont();
subTitleFont_.setPixelSize(5);
// compute text positions
QRectF titleBounds = QFontMetricsF(titleFont_).boundingRect(titleText_.c_str());
QRectF subTitleBounds = QFontMetricsF(subTitleFont_).boundingRect(subTitleText_.c_str());
float titleOffsetX = (titleBounds.width()-bodyRect_.width()-iconScale_)*0.5f;
float titleOffsetY = subTitleBounds.height()*0.5f+titlePadding_+(-(subTitleBounds.height()*0.5+titleBounds.height()+titlePadding_)+bodyRect_.height())*0.5f;
// float titleOffsetY = (bodyRect_.height())*0.5f;
// titleOffsetY -= subTitleBounds.height()*0.5f;
float subTitleOffsetX = titleOffsetX;
float subTitleOffsetY = (-(subTitleBounds.height()*0.5+titleBounds.height()+titlePadding_)+bodyRect_.height())*0.5f;
titleRect_ = bodyRect_.adjusted(-titleOffsetX, titleOffsetY, -titleOffsetX, titleOffsetY);
subTitleRect_ = bodyRect_.adjusted(-subTitleOffsetX, subTitleOffsetY, -subTitleOffsetX, subTitleOffsetY);
}
void NodeGraphic::initIcon()
{
icon_ = new NodeIconGraphic(":/node-icons/grid.svg", this);
// icon_ = new NodeIconGraphic("/home/parker/MyRepos/masters/static/icons/icon-main-white.svg", this);
icon_->setScale(1.0f/icon_->boundingRect().width()*iconScale_);
// icon_->setScale(0.01);
icon_->setPos(titleRect_.left()-iconScale_-iconPadding_, -iconScale_*0.5f);
}
void NodeGraphic::initFlagButtons()
{
displayFlagButton_ = new DisplayFlagButton(this);
float padding = 2;
displayFlagButton_->setPos(QPointF(bodyRect_.right()-displayFlagButton_->getWidth()/2.0f-padding, bodyRect_.center().y()));
}
void NodeGraphic::initSockets()
{
auto* socketInput = new SocketGraphic(SocketGraphic::SocketType::Input, this);
socketInput->setPos(getSocketPosition(0, SocketGraphic::SocketType::Input));
inputs_.push_back(socketInput);
auto* socketOutput = new SocketGraphic(SocketGraphic::SocketType::Output, this);
socketOutput->setPos(getSocketPosition(0, SocketGraphic::SocketType::Output));
outputs_.push_back(socketOutput);
}
// void setInputEdge(NodeEdgeGraphic* edge, int indx)
// {
// }
// void setOutputEdge(NodeEdgeGraphic* edge, int indx)
// {
// }
// void NodeGraphic::addEdge(NodeEdgeGraphic* edge)
// {
// edges_.push_back(edge);
// }
SocketGraphic* NodeGraphic::getInput(int indx) const
{
if(inputs_.size()==0)
{
throw std::out_of_range("Can't access inputs when node has no inputs: " + std::to_string(indx));
}
else if(indx>inputs_.size()-1)
{
throw std::out_of_range("Can't access input: " + std::to_string(indx));
}
return inputs_.at(indx);
}
SocketGraphic* NodeGraphic::getOutput(int indx) const
{
if(outputs_.size()==0)
{
throw std::out_of_range("Can't access outputs when node has no outputs: " + std::to_string(indx));
}
else if(indx>inputs_.size()-1)
{
throw std::out_of_range("Can't access input: " + std::to_string(indx));
}
return outputs_.at(indx);
}
QRectF NodeGraphic::boundingRect() const
{
QRectF boundRect = bodyRect_;
float padding = 0;
boundRect.adjust(-padding, -padding, padding, padding);
return boundRect;
}
void NodeGraphic::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
// default outline
QPen defaultPen = Qt::NoPen;
defaultPen.setWidth(1);
// outline when selected
QPen selectedPen = QPen("#edd044");
// choose outline
if(isSelected()) painter->setPen(selectedPen);
else painter->setPen(defaultPen);
// set fill
QBrush whiteBrush = QBrush("white");
painter->setBrush(QBrush(QColor("#1b1b1b")));
painter->drawRoundedRect(bodyRect_, 5, 5);
painter->setPen(QPen(QColor("white")));
painter->setFont(titleFont_);
// painter->setPen(QPen(QColor("#d2d2d2")));
painter->setPen(QPen(QColor("white")));
painter->drawText(titleRect_, Qt::AlignLeft, titleText_.c_str());
painter->setFont(subTitleFont_);
painter->drawText(subTitleRect_, Qt::AlignLeft, subTitleText_.c_str());
}
void NodeGraphic::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsItem::mouseMoveEvent(event);
updatePositions(event->scenePos());
}
// void NodeGraphic::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
// {
// updatePositions(event->scenePos());
// QGraphicsItem::mouseReleaseEvent(event);
// }
void NodeGraphic::updatePositions(QPointF pos)
{
// NOTE: in the future I might store socket ids as internal member variables,
// but for now I'm just going based on order
for(int socketIndex=0; socketIndex<inputs_.size(); ++socketIndex)
{
inputs_[socketIndex]->posChanged(getSocketScenePosition(socketIndex, SocketGraphic::SocketType::Input));
}
for(int socketIndex=0; socketIndex<outputs_.size(); ++socketIndex)
{
outputs_[socketIndex]->posChanged(getSocketScenePosition(socketIndex, SocketGraphic::SocketType::Output));
}
}
QPointF NodeGraphic::getSocketPosition(int socketIndex, SocketGraphic::SocketType socketType)
{
float xPos, yPos;
xPos = bodyRect_.center().x();
yPos = socketType == SocketGraphic::SocketType::Input ? bodyRect_.top() : bodyRect_.bottom();
return QPointF(xPos, yPos);
}
QPointF NodeGraphic::getSocketScenePosition(int socketIndex, SocketGraphic::SocketType socketType)
{
return this->pos()+getSocketPosition(socketIndex, socketType);
}
QRectF NodeGraphic::getBodyRect()
{
return bodyRect_;
}
// QVariant NodeGraphic::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
// {
// if (change == ItemPositionChange && scene()) {
// for(auto socket : inputs_)
// {
// socket->posChanged(value.toPointF());
// }
// for(auto socket : outputs_)
// {
// socket->posChanged(value.toPointF());
// }
// };
// return QGraphicsItem::itemChange(change, value);
// }