ui: styled nodes in graph view
This change styles the nodes in the QtGraphView. Since Stylesheets can't be applied to QGraphicsItems, the style implementation was done in the source files. The containers for public/protected/private nodes are now subclassed from QtGraphNode as QtGraphNodeAccess, including a helper class QtAccessArrow for indicating the opened/colapsed state.
This commit is contained in:
@@ -1,46 +1,50 @@
|
||||
#include "qt/view/graphElements/QtGraphNode.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
#include <QBrush>
|
||||
#include <QFontMetrics>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsSceneEvent>
|
||||
#include <QPen>
|
||||
|
||||
#include "qt/view/graphElements/QtGraphEdge.h"
|
||||
#include "utility/messaging/type/MessageActivateToken.h"
|
||||
|
||||
#include "qt/graphics/QtGraphicsRoundedRectItem.h"
|
||||
#include "qt/utility/QtDeviceScaledPixmap.h"
|
||||
#include "qt/view/graphElements/nodeComponents/QtGraphNodeComponent.h"
|
||||
#include "qt/view/graphElements/QtGraphEdge.h"
|
||||
|
||||
QtGraphNode::QtGraphNode(const Node* data, TokenComponentAccess::AccessType accessType)
|
||||
: GraphNode(data)
|
||||
QtGraphNode::QtGraphNode()
|
||||
: GraphNode(nullptr)
|
||||
, m_undefinedRect(nullptr)
|
||||
, m_padding(0, 0, 0, 0)
|
||||
, m_spacing(8)
|
||||
, m_isActive(false)
|
||||
, m_padding(10, 10)
|
||||
, m_contentHidden(false)
|
||||
, m_isHovering(false)
|
||||
{
|
||||
m_text = new QGraphicsTextItem(this);
|
||||
m_text->setPos(0, 0);
|
||||
this->setPen(QPen(Qt::transparent));
|
||||
|
||||
std::stringstream text;
|
||||
QBrush brush(Qt::white);
|
||||
m_rect = new QtGraphicsRoundedRectItem(this);
|
||||
m_text = new QGraphicsSimpleTextItem(this);
|
||||
}
|
||||
|
||||
if (data)
|
||||
{
|
||||
text << data->getId() << ": " << data->getName();
|
||||
brush.setColor(Qt::lightGray);
|
||||
}
|
||||
else
|
||||
{
|
||||
text << TokenComponentAccess::getAccessString(accessType);
|
||||
}
|
||||
QtGraphNode::QtGraphNode(const Node* data)
|
||||
: GraphNode(data)
|
||||
, m_undefinedRect(nullptr)
|
||||
, m_padding(0, 0, 0, 0)
|
||||
, m_spacing(8)
|
||||
, m_isActive(false)
|
||||
, m_isHovering(false)
|
||||
{
|
||||
this->setPen(QPen(Qt::transparent));
|
||||
|
||||
m_text->setPlainText(QString(text.str().c_str()));
|
||||
this->setBrush(brush);
|
||||
m_rect = new QtGraphicsRoundedRectItem(this);
|
||||
m_text = new QGraphicsSimpleTextItem(this);
|
||||
|
||||
m_baseSize.x = QFontMetrics(m_text->font()).width(m_text->toPlainText()) + 10;
|
||||
m_baseSize.y = 25;
|
||||
|
||||
m_currentSize = m_baseSize;
|
||||
|
||||
this->setRect(0, 0, m_baseSize.x, m_baseSize.y);
|
||||
this->setAcceptHoverEvents(true);
|
||||
|
||||
this->setName(data->getName());
|
||||
this->setStyle();
|
||||
|
||||
this->setSize(m_baseSize);
|
||||
}
|
||||
|
||||
QtGraphNode::~QtGraphNode()
|
||||
@@ -57,7 +61,12 @@ QtGraphNode::~QtGraphNode()
|
||||
|
||||
std::string QtGraphNode::getName() const
|
||||
{
|
||||
return m_text->toPlainText().toStdString();
|
||||
return m_text->text().toStdString();
|
||||
}
|
||||
|
||||
void QtGraphNode::setName(const std::string& name)
|
||||
{
|
||||
m_text->setText(QString::fromStdString(name));
|
||||
}
|
||||
|
||||
Vec2i QtGraphNode::getPosition() const
|
||||
@@ -82,46 +91,17 @@ Vec2i QtGraphNode::getSize() const
|
||||
return m_currentSize;
|
||||
}
|
||||
|
||||
bool QtGraphNode::getIsActive() const
|
||||
void QtGraphNode::setSize(Vec2i size)
|
||||
{
|
||||
return m_isActive;
|
||||
}
|
||||
m_currentSize = size;
|
||||
|
||||
void QtGraphNode::setIsActive(bool isActive)
|
||||
{
|
||||
m_isActive = isActive;
|
||||
this->setRect(0, 0, size.x, size.y);
|
||||
m_rect->setRect(0, 0, size.x, size.y);
|
||||
|
||||
QPen p = this->pen();
|
||||
if (isActive)
|
||||
if (m_undefinedRect)
|
||||
{
|
||||
p.setWidth(2);
|
||||
m_undefinedRect->setRect(1, 1, size.x - 2, size.y - 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
p.setWidth(1);
|
||||
}
|
||||
this->setPen(p);
|
||||
}
|
||||
|
||||
QtGraphNode* QtGraphNode::getParent() const
|
||||
{
|
||||
return m_parentNode.lock().get();
|
||||
}
|
||||
|
||||
void QtGraphNode::setParent(std::weak_ptr<QtGraphNode> parentNode)
|
||||
{
|
||||
m_parentNode = parentNode;
|
||||
|
||||
std::shared_ptr<QtGraphNode> parent = parentNode.lock();
|
||||
if (parent != NULL)
|
||||
{
|
||||
QGraphicsRectItem::setParentItem(parent.get());
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::addComponent(const std::shared_ptr<QtGraphNodeComponent>& component)
|
||||
{
|
||||
m_components.push_back(component);
|
||||
}
|
||||
|
||||
bool QtGraphNode::addOutEdge(const std::shared_ptr<GraphEdge>& edge)
|
||||
@@ -173,72 +153,6 @@ void QtGraphNode::removeOutEdge(GraphEdge* edge)
|
||||
}
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<GraphNode>> QtGraphNode::getSubNodes() const
|
||||
{
|
||||
return m_subNodes;
|
||||
}
|
||||
|
||||
void QtGraphNode::addSubNode(const std::shared_ptr<GraphNode>& node)
|
||||
{
|
||||
m_subNodes.push_back(node);
|
||||
|
||||
rebuildLayout();
|
||||
}
|
||||
|
||||
void QtGraphNode::notifyParentMoved()
|
||||
{
|
||||
notifyEdgesAfterMove();
|
||||
}
|
||||
|
||||
void QtGraphNode::hideContent()
|
||||
{
|
||||
for (std::shared_ptr<GraphNode> node : m_subNodes)
|
||||
{
|
||||
node->hideContent();
|
||||
|
||||
if (node->getTokenId() && node->getEdgeAndActiveCountRecursive() <= 0)
|
||||
{
|
||||
node->hide();
|
||||
}
|
||||
}
|
||||
|
||||
m_contentHidden = true;
|
||||
|
||||
onChildSizeChanged();
|
||||
}
|
||||
|
||||
void QtGraphNode::showContent()
|
||||
{
|
||||
for (std::shared_ptr<GraphNode> node : m_subNodes)
|
||||
{
|
||||
node->show();
|
||||
}
|
||||
|
||||
m_contentHidden = false;
|
||||
|
||||
onChildSizeChanged();
|
||||
}
|
||||
|
||||
void QtGraphNode::hide()
|
||||
{
|
||||
QGraphicsRectItem::hide();
|
||||
}
|
||||
|
||||
void QtGraphNode::show()
|
||||
{
|
||||
QGraphicsRectItem::show();
|
||||
}
|
||||
|
||||
bool QtGraphNode::isHidden()
|
||||
{
|
||||
return !QGraphicsRectItem::isVisible();
|
||||
}
|
||||
|
||||
bool QtGraphNode::contentIsHidden()
|
||||
{
|
||||
return m_contentHidden;
|
||||
}
|
||||
|
||||
unsigned int QtGraphNode::getOutEdgeCount() const
|
||||
{
|
||||
return m_outEdges.size();
|
||||
@@ -249,6 +163,49 @@ unsigned int QtGraphNode::getInEdgeCount() const
|
||||
return m_inEdges.size();
|
||||
}
|
||||
|
||||
bool QtGraphNode::getIsActive() const
|
||||
{
|
||||
return m_isActive;
|
||||
}
|
||||
|
||||
void QtGraphNode::setIsActive(bool isActive)
|
||||
{
|
||||
m_isActive = isActive;
|
||||
|
||||
setStyle();
|
||||
}
|
||||
|
||||
QtGraphNode* QtGraphNode::getParent() const
|
||||
{
|
||||
return m_parentNode.lock().get();
|
||||
}
|
||||
|
||||
void QtGraphNode::setParent(std::weak_ptr<QtGraphNode> parentNode)
|
||||
{
|
||||
m_parentNode = parentNode;
|
||||
|
||||
std::shared_ptr<QtGraphNode> parent = parentNode.lock();
|
||||
if (parent != NULL)
|
||||
{
|
||||
QGraphicsRectItem::setParentItem(parent.get());
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::addComponent(const std::shared_ptr<QtGraphNodeComponent>& component)
|
||||
{
|
||||
m_components.push_back(component);
|
||||
}
|
||||
|
||||
std::list<std::shared_ptr<QtGraphNode>> QtGraphNode::getSubNodes() const
|
||||
{
|
||||
return m_subNodes;
|
||||
}
|
||||
|
||||
void QtGraphNode::addSubNode(const std::shared_ptr<QtGraphNode>& node)
|
||||
{
|
||||
m_subNodes.push_back(node);
|
||||
}
|
||||
|
||||
unsigned int QtGraphNode::getEdgeAndActiveCountRecursive() const
|
||||
{
|
||||
unsigned int result = 0;
|
||||
@@ -258,7 +215,7 @@ unsigned int QtGraphNode::getEdgeAndActiveCountRecursive() const
|
||||
result++;
|
||||
}
|
||||
|
||||
for (std::shared_ptr<GraphNode> node : m_subNodes)
|
||||
for (std::shared_ptr<QtGraphNode> node : m_subNodes)
|
||||
{
|
||||
result += node->getEdgeAndActiveCountRecursive();
|
||||
}
|
||||
@@ -268,9 +225,24 @@ unsigned int QtGraphNode::getEdgeAndActiveCountRecursive() const
|
||||
return result;
|
||||
}
|
||||
|
||||
void QtGraphNode::hideContent()
|
||||
{
|
||||
for (std::shared_ptr<QtGraphNode> node : m_subNodes)
|
||||
{
|
||||
node->hideContent();
|
||||
|
||||
if (node->getTokenId() && node->getEdgeAndActiveCountRecursive() <= 0)
|
||||
{
|
||||
node->hide();
|
||||
}
|
||||
}
|
||||
|
||||
rebuildLayout();
|
||||
}
|
||||
|
||||
void QtGraphNode::onClick()
|
||||
{
|
||||
if (m_data)
|
||||
if (m_data && !m_data->isType(Node::NODE_UNDEFINED | Node::NODE_NAMESPACE))
|
||||
{
|
||||
MessageActivateToken(m_data->getId()).dispatch();
|
||||
}
|
||||
@@ -335,87 +307,221 @@ void QtGraphNode::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
|
||||
|
||||
void QtGraphNode::hoverEnterEvent(QGraphicsSceneHoverEvent* event)
|
||||
{
|
||||
if (m_data)
|
||||
{
|
||||
bool isActive = m_isActive;
|
||||
this->setIsActive(true);
|
||||
m_isActive = isActive;
|
||||
}
|
||||
m_isHovering = true;
|
||||
setStyle();
|
||||
}
|
||||
|
||||
void QtGraphNode::hoverLeaveEvent(QGraphicsSceneHoverEvent* event)
|
||||
{
|
||||
this->setIsActive(m_isActive);
|
||||
m_isHovering = false;
|
||||
setStyle();
|
||||
}
|
||||
|
||||
void QtGraphNode::notifyEdgesAfterMove()
|
||||
{
|
||||
for (std::list<std::shared_ptr<GraphEdge>>::iterator it = m_outEdges.begin(); it != m_outEdges.end(); it++)
|
||||
for (const std::shared_ptr<GraphEdge>& edge : m_outEdges)
|
||||
{
|
||||
(*it)->ownerMoved();
|
||||
edge->ownerMoved();
|
||||
}
|
||||
|
||||
std::list<std::weak_ptr<GraphEdge>>::iterator it2 = m_inEdges.begin();
|
||||
while (it2 != m_inEdges.end())
|
||||
for (const std::weak_ptr<GraphEdge>& e : m_inEdges)
|
||||
{
|
||||
std::shared_ptr<GraphEdge> edge = it2->lock();
|
||||
if (edge.get() != NULL)
|
||||
{
|
||||
edge->targetMoved();
|
||||
++it2;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_inEdges.erase(it2++);
|
||||
}
|
||||
std::shared_ptr<GraphEdge> edge = e.lock();
|
||||
if (edge)
|
||||
{
|
||||
edge->targetMoved();
|
||||
}
|
||||
}
|
||||
|
||||
for (std::list<std::shared_ptr<GraphNode>>::iterator it3 = m_subNodes.begin(); it3 != m_subNodes.end(); it3++)
|
||||
for (const std::shared_ptr<QtGraphNode>& node : m_subNodes)
|
||||
{
|
||||
(*it3)->notifyParentMoved();
|
||||
node->notifyEdgesAfterMove();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::notifyParentNodeAfterSizeChanged()
|
||||
void QtGraphNode::onSizeChanged()
|
||||
{
|
||||
rebuildLayout();
|
||||
|
||||
std::shared_ptr<QtGraphNode> parentNode = m_parentNode.lock();
|
||||
|
||||
if (parentNode != NULL)
|
||||
{
|
||||
parentNode->onChildSizeChanged();
|
||||
parentNode->onSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::onChildSizeChanged()
|
||||
{
|
||||
rebuildLayout();
|
||||
|
||||
notifyParentNodeAfterSizeChanged();
|
||||
}
|
||||
|
||||
void QtGraphNode::rebuildLayout()
|
||||
{
|
||||
int nextYPos = m_baseSize.y;
|
||||
int newWidth = m_baseSize.x;
|
||||
setStyle();
|
||||
|
||||
for (const std::shared_ptr<GraphNode>& node : m_subNodes)
|
||||
Vec2i newSize(m_baseSize);
|
||||
newSize.y = newSize.y - m_padding.w;
|
||||
|
||||
for (const std::shared_ptr<QtGraphNode>& node : m_subNodes)
|
||||
{
|
||||
if (!node->isHidden())
|
||||
if (node->isVisible())
|
||||
{
|
||||
node->setPosition(this->getPosition() + Vec2i(m_padding.x, nextYPos));
|
||||
nextYPos += node->getSize().y + m_padding.y;
|
||||
node->setPosition(this->getPosition() + Vec2i(m_padding.x, m_spacing + newSize.y));
|
||||
newSize.y = newSize.y + m_spacing + node->getSize().y;
|
||||
|
||||
int tmpWidth = (node->getPosition().x - getPosition().x) + node->getSize().x + m_padding.x;
|
||||
int tmpWidth = node->getSize().x + m_padding.x + m_padding.z;
|
||||
|
||||
if (tmpWidth > newWidth)
|
||||
if (tmpWidth > newSize.x)
|
||||
{
|
||||
newWidth = tmpWidth;
|
||||
newSize.x = tmpWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_currentSize.x = newWidth;
|
||||
m_currentSize.y = nextYPos;
|
||||
newSize.y = newSize.y + m_padding.w;
|
||||
setSize(newSize);
|
||||
}
|
||||
|
||||
this->setRect(0, 0, m_currentSize.x, m_currentSize.y);
|
||||
void QtGraphNode::setStyle()
|
||||
{
|
||||
if (!m_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QColor color = Qt::lightGray;
|
||||
qreal radius = 0.0f;
|
||||
QFont font("Source Code Pro");
|
||||
QPen p(Qt::transparent);
|
||||
|
||||
bool undefined = false;
|
||||
bool useUndefinedColor = false;
|
||||
|
||||
switch (m_data->getType())
|
||||
{
|
||||
case Node::NODE_UNDEFINED:
|
||||
undefined = true;
|
||||
case Node::NODE_NAMESPACE:
|
||||
color = Qt::white;
|
||||
|
||||
p.setColor("#cc8d91");
|
||||
p.setWidth(1);
|
||||
|
||||
font.setPointSize(12);
|
||||
|
||||
radius = 20.0f;
|
||||
m_padding.x = m_padding.z = 15;
|
||||
m_padding.y = 6;
|
||||
m_padding.w = 15;
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_TYPE:
|
||||
undefined = true;
|
||||
case Node::NODE_STRUCT:
|
||||
case Node::NODE_CLASS:
|
||||
case Node::NODE_ENUM:
|
||||
case Node::NODE_TYPEDEF:
|
||||
if (m_isHovering)
|
||||
{
|
||||
m_rect->setShadow(QColor(0, 0, 0, 255), 5);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rect->setShadow(QColor(0, 0, 0, 128), 5);
|
||||
}
|
||||
|
||||
font.setPointSize(14);
|
||||
|
||||
color = "#ededed";
|
||||
if (m_subNodes.size())
|
||||
{
|
||||
radius = 20.0f;
|
||||
m_padding.x = m_padding.z = 15;
|
||||
m_padding.y = m_padding.w = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
radius = 10.0f;
|
||||
m_padding.x = m_padding.z = 8;
|
||||
m_padding.y = m_padding.w = 5;
|
||||
}
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_FUNCTION:
|
||||
undefined = true;
|
||||
useUndefinedColor = true;
|
||||
case Node::NODE_FUNCTION:
|
||||
case Node::NODE_METHOD:
|
||||
if (m_isActive || m_isHovering)
|
||||
{
|
||||
color = "#ffcc00";
|
||||
font.setWeight(QFont::Bold);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = "#ffe47a";
|
||||
}
|
||||
|
||||
font.setPointSize(11);
|
||||
|
||||
radius = 8.0f;
|
||||
m_padding.x = m_padding.z = 5;
|
||||
m_padding.y = m_padding.w = 3;
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_VARIABLE:
|
||||
undefined = true;
|
||||
useUndefinedColor = true;
|
||||
case Node::NODE_GLOBAL_VARIABLE:
|
||||
case Node::NODE_FIELD:
|
||||
if (m_isActive || m_isHovering)
|
||||
{
|
||||
color = "#62b29d";
|
||||
font.setWeight(QFont::Bold);
|
||||
}
|
||||
else
|
||||
{
|
||||
color = "#9ab4ad";
|
||||
}
|
||||
|
||||
font.setPointSize(11);
|
||||
|
||||
radius = 8.0f;
|
||||
m_padding.x = m_padding.z = 5;
|
||||
m_padding.y = m_padding.w = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_isActive)
|
||||
{
|
||||
p.setWidthF(1.5f);
|
||||
p.setColor("#3c3c3c");
|
||||
}
|
||||
|
||||
m_rect->setPen(p);
|
||||
m_rect->setBrush(QBrush(color));
|
||||
m_rect->setRadius(radius);
|
||||
|
||||
if (undefined)
|
||||
{
|
||||
QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/pattern.png");
|
||||
pixmap.scaleToHeight(10);
|
||||
|
||||
if (!m_undefinedRect)
|
||||
{
|
||||
m_undefinedRect = new QtGraphicsRoundedRectItem(this);
|
||||
}
|
||||
|
||||
p.setWidth(1);
|
||||
p.setColor(Qt::transparent);
|
||||
if (useUndefinedColor && !m_isActive)
|
||||
{
|
||||
p.setColor(color);
|
||||
}
|
||||
m_undefinedRect->setPen(p);
|
||||
m_undefinedRect->setBrush(QBrush(pixmap.pixmap()));
|
||||
m_undefinedRect->setRadius(radius);
|
||||
}
|
||||
|
||||
m_text->setFont(font);
|
||||
m_text->setPos(m_padding.x, m_padding.y);
|
||||
|
||||
m_baseSize.x = QFontMetrics(m_text->font()).width(m_text->text()) + m_padding.x + m_padding.z;
|
||||
m_baseSize.y = QFontMetrics(m_text->font()).height() + m_padding.y + m_padding.w;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user