ui: moved subnode layouting from GraphView to GraphController
This change moves nested layouting of the Graph to GraphController. The DummyNodes get the correct size assigned, as well as a visible flag. Mouse interaction with the Graph is now handled via the GraphController, which makes it easier to undo them or reuse the changed state after graph updates.
This commit is contained in:
@@ -17,10 +17,7 @@
|
||||
QtGraphView::QtGraphView(ViewLayout* viewLayout)
|
||||
: GraphView(viewLayout)
|
||||
, m_rebuildGraphFunctor(
|
||||
std::bind(
|
||||
&QtGraphView::doRebuildGraph, this,
|
||||
std::placeholders::_1, std::placeholders::_2,
|
||||
std::placeholders::_3, std::placeholders::_4))
|
||||
std::bind(&QtGraphView::doRebuildGraph, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3))
|
||||
, m_clearFunctor(std::bind(&QtGraphView::doClear, this))
|
||||
{
|
||||
}
|
||||
@@ -57,11 +54,10 @@ void QtGraphView::refreshView()
|
||||
|
||||
void QtGraphView::rebuildGraph(
|
||||
std::shared_ptr<Graph> graph,
|
||||
std::vector<Id> activeTokenIds,
|
||||
const std::vector<DummyNode>& nodes,
|
||||
const std::vector<DummyEdge>& edges
|
||||
){
|
||||
m_rebuildGraphFunctor(graph, activeTokenIds, nodes, edges);
|
||||
m_rebuildGraphFunctor(graph, nodes, edges);
|
||||
}
|
||||
|
||||
void QtGraphView::clear()
|
||||
@@ -69,22 +65,38 @@ void QtGraphView::clear()
|
||||
m_clearFunctor();
|
||||
}
|
||||
|
||||
QGraphicsView* QtGraphView::getView()
|
||||
GraphView::Metrics QtGraphView::getViewMetrics() const
|
||||
{
|
||||
GraphView::Metrics metrics;
|
||||
|
||||
QGraphicsView* view = getView();
|
||||
if (view == NULL)
|
||||
{
|
||||
return metrics;
|
||||
}
|
||||
|
||||
metrics.width = view->width();
|
||||
metrics.height = view->height();
|
||||
|
||||
metrics.typeNameCharWidth = QFontMetrics(QtGraphNode::getFontForNodeType(Node::NODE_CLASS)).width("QtGraphNode") / 11.0f;
|
||||
metrics.variableNameCharWidth = QFontMetrics(QtGraphNode::getFontForNodeType(Node::NODE_FIELD)).width("QtGraphNode") / 11.0f;
|
||||
metrics.functionNameCharWidth = QFontMetrics(QtGraphNode::getFontForNodeType(Node::NODE_METHOD)).width("QtGraphNode") / 11.0f;
|
||||
|
||||
return metrics;
|
||||
}
|
||||
|
||||
QGraphicsView* QtGraphView::getView() const
|
||||
{
|
||||
QWidget* widget = QtViewWidgetWrapper::getWidgetOfView(this);
|
||||
|
||||
QObjectList children = widget->children();
|
||||
|
||||
return widget->findChild<QGraphicsView*>("");
|
||||
}
|
||||
|
||||
void QtGraphView::doRebuildGraph(
|
||||
std::shared_ptr<Graph> graph,
|
||||
std::vector<Id> activeTokenIds,
|
||||
const std::vector<DummyNode>& nodes,
|
||||
const std::vector<DummyEdge>& edges
|
||||
){
|
||||
m_activeTokenIds = activeTokenIds;
|
||||
QGraphicsView* view = getView();
|
||||
|
||||
if (view == NULL)
|
||||
@@ -100,9 +112,11 @@ void QtGraphView::doRebuildGraph(
|
||||
// create nodes (or find existing nodes for re-use)
|
||||
for (unsigned int i = 0; i < nodes.size(); i++)
|
||||
{
|
||||
std::shared_ptr<QtGraphNode> newNode = createNodeRecursive(view, NULL, nodes[i]);
|
||||
newNode->setPosition(nodes[i].position);
|
||||
newNodes.push_back(newNode);
|
||||
std::shared_ptr<QtGraphNode> node = createNodeRecursive(view, NULL, nodes[i]);
|
||||
if (node)
|
||||
{
|
||||
newNodes.push_back(node);
|
||||
}
|
||||
}
|
||||
|
||||
doClear();
|
||||
@@ -117,18 +131,23 @@ void QtGraphView::doRebuildGraph(
|
||||
}
|
||||
}
|
||||
|
||||
// hide node content by default, must be done after all edges are created to keep subnodes with connections visible
|
||||
for (const std::shared_ptr<QtGraphNode>& node : m_nodes)
|
||||
if (graph)
|
||||
{
|
||||
node->hideContent();
|
||||
m_graph = graph;
|
||||
}
|
||||
|
||||
for (const std::shared_ptr<QtGraphEdge>& edge : m_edges)
|
||||
// Manually hover the items below the mouse cursor.
|
||||
view->scene()->setSceneRect(view->scene()->itemsBoundingRect());
|
||||
QPointF point = view->mapToScene(view->mapFromGlobal(QCursor::pos()));
|
||||
QGraphicsItem* item = view->scene()->itemAt(point, QTransform());
|
||||
if (item)
|
||||
{
|
||||
edge->updateLine();
|
||||
QtGraphNode* node = dynamic_cast<QtGraphNode*>(item->parentItem());
|
||||
if (node)
|
||||
{
|
||||
node->hoverEnter();
|
||||
}
|
||||
}
|
||||
|
||||
m_graph = graph;
|
||||
}
|
||||
|
||||
void QtGraphView::doClear()
|
||||
@@ -159,6 +178,11 @@ std::shared_ptr<QtGraphNode> QtGraphView::findNodeRecursive(const std::list<std:
|
||||
std::shared_ptr<QtGraphNode> QtGraphView::createNodeRecursive(
|
||||
QGraphicsView* view, std::shared_ptr<QtGraphNode> parentNode, const DummyNode& node
|
||||
){
|
||||
if (!node.visible)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::shared_ptr<QtGraphNode> newNode;
|
||||
if (node.data)
|
||||
{
|
||||
@@ -166,18 +190,17 @@ std::shared_ptr<QtGraphNode> QtGraphView::createNodeRecursive(
|
||||
}
|
||||
else
|
||||
{
|
||||
newNode = std::make_shared<QtGraphNodeAccess>(node.accessType);
|
||||
newNode = std::make_shared<QtGraphNodeAccess>(node.accessType, node.expanded, node.invisibleSubNodeCount);
|
||||
}
|
||||
|
||||
newNode->setPosition(node.position);
|
||||
newNode->setSize(node.size);
|
||||
newNode->setIsActive(node.active);
|
||||
|
||||
newNode->addComponent(std::make_shared<QtGraphNodeComponentClickable>(newNode));
|
||||
|
||||
view->scene()->addItem(newNode.get());
|
||||
|
||||
if (node.data && isActiveTokenId(node.data->getId()))
|
||||
{
|
||||
newNode->setIsActive(true);
|
||||
}
|
||||
|
||||
if (parentNode)
|
||||
{
|
||||
newNode->setParent(parentNode);
|
||||
@@ -190,9 +213,14 @@ std::shared_ptr<QtGraphNode> QtGraphView::createNodeRecursive(
|
||||
for (unsigned int i = 0; i < node.subNodes.size(); i++)
|
||||
{
|
||||
std::shared_ptr<QtGraphNode> subNode = createNodeRecursive(view, newNode, node.subNodes[i]);
|
||||
newNode->addSubNode(subNode);
|
||||
if (subNode)
|
||||
{
|
||||
newNode->addSubNode(subNode);
|
||||
}
|
||||
}
|
||||
|
||||
newNode->setStyle();
|
||||
|
||||
return newNode;
|
||||
}
|
||||
|
||||
@@ -204,8 +232,9 @@ std::shared_ptr<QtGraphEdge> QtGraphView::createEdge(QGraphicsView* view, const
|
||||
if (owner != NULL && target != NULL)
|
||||
{
|
||||
std::shared_ptr<QtGraphEdge> qtEdge = std::make_shared<QtGraphEdge>(owner, target, edge.data);
|
||||
bool added = owner->addOutEdge(qtEdge) | target->addInEdge(qtEdge);
|
||||
qtEdge->setIsActive(edge.active);
|
||||
|
||||
bool added = owner->addOutEdge(qtEdge) | target->addInEdge(qtEdge);
|
||||
if (!added)
|
||||
{
|
||||
return NULL;
|
||||
@@ -213,11 +242,6 @@ std::shared_ptr<QtGraphEdge> QtGraphView::createEdge(QGraphicsView* view, const
|
||||
|
||||
view->scene()->addItem(qtEdge.get());
|
||||
|
||||
if (isActiveTokenId(edge.data->getId()))
|
||||
{
|
||||
qtEdge->setIsActive(true);
|
||||
}
|
||||
|
||||
return qtEdge;
|
||||
}
|
||||
else
|
||||
@@ -226,8 +250,3 @@ std::shared_ptr<QtGraphEdge> QtGraphView::createEdge(QGraphicsView* view, const
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool QtGraphView::isActiveTokenId(Id tokenId) const
|
||||
{
|
||||
return find(m_activeTokenIds.begin(), m_activeTokenIds.end(), tokenId) != m_activeTokenIds.end();
|
||||
}
|
||||
|
||||
@@ -24,22 +24,15 @@ public:
|
||||
virtual void initView();
|
||||
virtual void refreshView();
|
||||
|
||||
virtual void rebuildGraph(
|
||||
std::shared_ptr<Graph> graph,
|
||||
std::vector<Id> activeTokenIds,
|
||||
const std::vector<DummyNode>& nodes,
|
||||
const std::vector<DummyEdge>& edges);
|
||||
|
||||
virtual void rebuildGraph(std::shared_ptr<Graph> graph, const std::vector<DummyNode>& nodes, const std::vector<DummyEdge>& edges);
|
||||
virtual void clear();
|
||||
|
||||
private:
|
||||
QGraphicsView* getView();
|
||||
virtual GraphView::Metrics getViewMetrics() const;
|
||||
|
||||
void doRebuildGraph(
|
||||
std::shared_ptr<Graph> graph,
|
||||
std::vector<Id> activeTokenIds,
|
||||
const std::vector<DummyNode>& nodes,
|
||||
const std::vector<DummyEdge>& edges);
|
||||
private:
|
||||
QGraphicsView* getView() const;
|
||||
|
||||
void doRebuildGraph(std::shared_ptr<Graph> graph, const std::vector<DummyNode>& nodes, const std::vector<DummyEdge>& edges);
|
||||
void doClear();
|
||||
|
||||
std::shared_ptr<QtGraphNode> findNodeRecursive(const std::list<std::shared_ptr<QtGraphNode>>& nodes, Id tokenId);
|
||||
@@ -48,16 +41,10 @@ private:
|
||||
QGraphicsView* view, std::shared_ptr<QtGraphNode> parentNode, const DummyNode& node);
|
||||
std::shared_ptr<QtGraphEdge> createEdge(QGraphicsView* view, const DummyEdge& edge);
|
||||
|
||||
bool isActiveTokenId(Id tokenId) const;
|
||||
|
||||
QtThreadedFunctor<
|
||||
std::shared_ptr<Graph>, std::vector<Id>, const std::vector<DummyNode>&, const std::vector<DummyEdge>&
|
||||
> m_rebuildGraphFunctor;
|
||||
|
||||
QtThreadedFunctor<std::shared_ptr<Graph>, const std::vector<DummyNode>&, const std::vector<DummyEdge>&> m_rebuildGraphFunctor;
|
||||
QtThreadedFunctor<void> m_clearFunctor;
|
||||
|
||||
std::shared_ptr<Graph> m_graph;
|
||||
std::vector<Id> m_activeTokenIds;
|
||||
|
||||
std::list<std::shared_ptr<QtGraphEdge>> m_edges;
|
||||
std::list<std::shared_ptr<QtGraphNode>> m_nodes;
|
||||
|
||||
@@ -1,22 +1,55 @@
|
||||
#include "qt/view/graphElements/QtGraphNode.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QFontMetrics>
|
||||
#include <QGraphicsSceneEvent>
|
||||
#include <QPen>
|
||||
|
||||
#include "utility/messaging/type/MessageActivateToken.h"
|
||||
#include "utility/messaging/type/MessageGraphNodeMove.h"
|
||||
|
||||
#include "qt/graphics/QtGraphicsRoundedRectItem.h"
|
||||
#include "qt/utility/QtDeviceScaledPixmap.h"
|
||||
#include "qt/view/graphElements/nodeComponents/QtGraphNodeComponent.h"
|
||||
#include "qt/view/graphElements/QtGraphEdge.h"
|
||||
|
||||
QFont QtGraphNode::getFontForNodeType(Node::NodeType type)
|
||||
{
|
||||
QFont font("Source Code Pro");
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case Node::NODE_UNDEFINED:
|
||||
case Node::NODE_NAMESPACE:
|
||||
font.setPointSize(12);
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_TYPE:
|
||||
case Node::NODE_STRUCT:
|
||||
case Node::NODE_CLASS:
|
||||
case Node::NODE_ENUM:
|
||||
case Node::NODE_TYPEDEF:
|
||||
font.setPointSize(14);
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_FUNCTION:
|
||||
case Node::NODE_FUNCTION:
|
||||
case Node::NODE_METHOD:
|
||||
font.setPointSize(11);
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_VARIABLE:
|
||||
case Node::NODE_GLOBAL_VARIABLE:
|
||||
case Node::NODE_FIELD:
|
||||
font.setPointSize(11);
|
||||
break;
|
||||
}
|
||||
|
||||
return font;
|
||||
}
|
||||
|
||||
QtGraphNode::QtGraphNode()
|
||||
: GraphNode(nullptr)
|
||||
, m_undefinedRect(nullptr)
|
||||
, m_padding(0, 0, 0, 0)
|
||||
, m_spacing(8)
|
||||
, m_isActive(false)
|
||||
, m_isHovering(false)
|
||||
{
|
||||
@@ -29,8 +62,6 @@ QtGraphNode::QtGraphNode()
|
||||
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)
|
||||
{
|
||||
@@ -42,9 +73,6 @@ QtGraphNode::QtGraphNode(const Node* data)
|
||||
this->setAcceptHoverEvents(true);
|
||||
|
||||
this->setName(data->getName());
|
||||
this->setStyle();
|
||||
|
||||
this->setSize(m_baseSize);
|
||||
}
|
||||
|
||||
QtGraphNode::~QtGraphNode()
|
||||
@@ -66,7 +94,7 @@ Vec2i QtGraphNode::getPosition() const
|
||||
return Vec2i(this->scenePos().x(), this->scenePos().y());
|
||||
}
|
||||
|
||||
void QtGraphNode::setPosition(const Vec2i& position)
|
||||
bool QtGraphNode::setPosition(const Vec2i& position)
|
||||
{
|
||||
Vec2i currentPosition = getPosition();
|
||||
Vec2i offset = position - currentPosition;
|
||||
@@ -75,17 +103,28 @@ void QtGraphNode::setPosition(const Vec2i& position)
|
||||
{
|
||||
this->moveBy(offset.x, offset.y);
|
||||
notifyEdgesAfterMove();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void QtGraphNode::moveTo(const Vec2i& position)
|
||||
{
|
||||
if (setPosition(position) && m_data)
|
||||
{
|
||||
MessageGraphNodeMove(m_data->getId(), position).dispatch();
|
||||
}
|
||||
}
|
||||
|
||||
Vec2i QtGraphNode::getSize() const
|
||||
{
|
||||
return m_currentSize;
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void QtGraphNode::setSize(Vec2i size)
|
||||
void QtGraphNode::setSize(const Vec2i& size)
|
||||
{
|
||||
m_currentSize = size;
|
||||
m_size = size;
|
||||
|
||||
this->setRect(0, 0, size.x, size.y);
|
||||
m_rect->setRect(0, 0, size.x, size.y);
|
||||
@@ -206,38 +245,143 @@ void QtGraphNode::addSubNode(const std::shared_ptr<QtGraphNode>& node)
|
||||
m_subNodes.push_back(node);
|
||||
}
|
||||
|
||||
unsigned int QtGraphNode::getEdgeAndActiveCountRecursive() const
|
||||
void QtGraphNode::setStyle()
|
||||
{
|
||||
unsigned int result = 0;
|
||||
if (!m_data)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
QColor color = Qt::lightGray;
|
||||
qreal radius = 0.0f;
|
||||
QPen p(Qt::transparent);
|
||||
QFont font(getFontForNodeType(m_data->getType()));
|
||||
|
||||
bool undefined = false;
|
||||
bool useUndefinedColor = false;
|
||||
|
||||
Vec2i padding;
|
||||
|
||||
switch (m_data->getType())
|
||||
{
|
||||
case Node::NODE_UNDEFINED:
|
||||
undefined = true;
|
||||
case Node::NODE_NAMESPACE:
|
||||
color = Qt::white;
|
||||
|
||||
p.setColor("#cc8d91");
|
||||
p.setWidth(1);
|
||||
|
||||
radius = 20.0f;
|
||||
padding.x = 15;
|
||||
padding.y = 6;
|
||||
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);
|
||||
}
|
||||
|
||||
color = "#ededed";
|
||||
if (m_subNodes.size())
|
||||
{
|
||||
radius = 20.0f;
|
||||
padding.x = 15;
|
||||
padding.y = 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
radius = 10.0f;
|
||||
padding.x = 8;
|
||||
padding.y = 4;
|
||||
}
|
||||
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";
|
||||
}
|
||||
|
||||
radius = 8.0f;
|
||||
padding.x = 5;
|
||||
padding.y = 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";
|
||||
}
|
||||
|
||||
radius = 8.0f;
|
||||
padding.x = 5;
|
||||
padding.y = 3;
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_isActive)
|
||||
{
|
||||
result++;
|
||||
p.setWidthF(1.5f);
|
||||
p.setColor("#3c3c3c");
|
||||
}
|
||||
|
||||
for (std::shared_ptr<QtGraphNode> node : m_subNodes)
|
||||
m_rect->setPen(p);
|
||||
m_rect->setBrush(QBrush(color));
|
||||
m_rect->setRadius(radius);
|
||||
|
||||
if (undefined)
|
||||
{
|
||||
result += node->getEdgeAndActiveCountRecursive();
|
||||
}
|
||||
QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/pattern.png");
|
||||
pixmap.scaleToHeight(10);
|
||||
|
||||
result += (getInEdgeCount() + getOutEdgeCount());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void QtGraphNode::hideContent()
|
||||
{
|
||||
for (std::shared_ptr<QtGraphNode> node : m_subNodes)
|
||||
{
|
||||
node->hideContent();
|
||||
|
||||
if (node->getTokenId() && node->getEdgeAndActiveCountRecursive() <= 0)
|
||||
if (!m_undefinedRect)
|
||||
{
|
||||
node->hide();
|
||||
m_undefinedRect = new QtGraphicsRoundedRectItem(this);
|
||||
setSize(getSize());
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
rebuildLayout();
|
||||
m_text->setFont(font);
|
||||
m_text->setPos(padding.x, padding.y);
|
||||
}
|
||||
|
||||
void QtGraphNode::onClick()
|
||||
@@ -248,6 +392,17 @@ void QtGraphNode::onClick()
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::hoverEnter()
|
||||
{
|
||||
hoverEnterEvent(nullptr);
|
||||
|
||||
QtGraphNode* parent = getParent();
|
||||
if (parent)
|
||||
{
|
||||
parent->hoverEnter();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::mousePressEvent(QGraphicsSceneMouseEvent* event)
|
||||
{
|
||||
event->ignore();
|
||||
@@ -338,190 +493,3 @@ void QtGraphNode::notifyEdgesAfterMove()
|
||||
node->notifyEdgesAfterMove();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::onSizeChanged()
|
||||
{
|
||||
rebuildLayout();
|
||||
|
||||
std::shared_ptr<QtGraphNode> parentNode = m_parentNode.lock();
|
||||
|
||||
if (parentNode != NULL)
|
||||
{
|
||||
parentNode->onSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphNode::rebuildLayout()
|
||||
{
|
||||
setStyle();
|
||||
|
||||
Vec2i newSize(m_baseSize);
|
||||
newSize.y = newSize.y - m_padding.w;
|
||||
|
||||
for (const std::shared_ptr<QtGraphNode>& node : m_subNodes)
|
||||
{
|
||||
if (node->isVisible())
|
||||
{
|
||||
node->setPosition(this->getPosition() + Vec2i(m_padding.x, m_spacing + newSize.y));
|
||||
newSize.y = newSize.y + m_spacing + node->getSize().y;
|
||||
|
||||
int tmpWidth = node->getSize().x + m_padding.x + m_padding.z;
|
||||
|
||||
if (tmpWidth > newSize.x)
|
||||
{
|
||||
newSize.x = tmpWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
newSize.y = newSize.y + m_padding.w;
|
||||
setSize(newSize);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef QT_GRAPH_NODE_H
|
||||
#define QT_GRAPH_NODE_H
|
||||
|
||||
#include <QFontMetrics>
|
||||
#include <QGraphicsItem>
|
||||
|
||||
#include "component/view/graphElements/GraphNode.h"
|
||||
@@ -14,6 +15,8 @@ class QtGraphNode
|
||||
, public QGraphicsRectItem
|
||||
{
|
||||
public:
|
||||
static QFont getFontForNodeType(Node::NodeType type);
|
||||
|
||||
QtGraphNode();
|
||||
QtGraphNode(const Node* data);
|
||||
virtual ~QtGraphNode();
|
||||
@@ -22,10 +25,11 @@ public:
|
||||
void setName(const std::string& name);
|
||||
|
||||
virtual Vec2i getPosition() const;
|
||||
virtual void setPosition(const Vec2i& position);
|
||||
virtual bool setPosition(const Vec2i& position);
|
||||
virtual void moveTo(const Vec2i& position);
|
||||
|
||||
virtual Vec2i getSize() const;
|
||||
virtual void setSize(Vec2i size);
|
||||
virtual void setSize(const Vec2i& size);
|
||||
|
||||
virtual Vec4i getBoundingRect() const;
|
||||
virtual Vec4i getParentBoundingRect() const;
|
||||
@@ -45,16 +49,12 @@ public:
|
||||
void addComponent(const std::shared_ptr<QtGraphNodeComponent>& component);
|
||||
|
||||
std::list<std::shared_ptr<QtGraphNode>> getSubNodes() const;
|
||||
void addSubNode(const std::shared_ptr<QtGraphNode>& node);
|
||||
virtual void addSubNode(const std::shared_ptr<QtGraphNode>& node);
|
||||
|
||||
/**
|
||||
* @brief Returns the count of all connected edges and active nodes (including sub nodes)
|
||||
*/
|
||||
unsigned int getEdgeAndActiveCountRecursive() const;
|
||||
|
||||
virtual void hideContent();
|
||||
void setStyle();
|
||||
|
||||
virtual void onClick();
|
||||
void hoverEnter();
|
||||
|
||||
protected:
|
||||
virtual void mousePressEvent(QGraphicsSceneMouseEvent* event);
|
||||
@@ -65,9 +65,6 @@ protected:
|
||||
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent* event);
|
||||
|
||||
void notifyEdgesAfterMove();
|
||||
void onSizeChanged();
|
||||
|
||||
virtual void rebuildLayout();
|
||||
|
||||
std::list<std::shared_ptr<GraphEdge>> m_outEdges;
|
||||
std::list<std::weak_ptr<GraphEdge>> m_inEdges;
|
||||
@@ -79,15 +76,9 @@ protected:
|
||||
QtGraphicsRoundedRectItem* m_rect;
|
||||
QtGraphicsRoundedRectItem* m_undefinedRect;
|
||||
|
||||
Vec2i m_baseSize;
|
||||
Vec2i m_currentSize;
|
||||
|
||||
Vec4i m_padding;
|
||||
int m_spacing;
|
||||
Vec2i m_size;
|
||||
|
||||
private:
|
||||
void setStyle();
|
||||
|
||||
std::list<std::shared_ptr<QtGraphNodeComponent>> m_components;
|
||||
|
||||
bool m_isActive;
|
||||
|
||||
@@ -4,79 +4,67 @@
|
||||
#include <QFontMetrics>
|
||||
#include <QPen>
|
||||
|
||||
#include "utility/messaging/type/MessageGraphNodeExpand.h"
|
||||
|
||||
#include "qt/graphics/QtGraphicsRoundedRectItem.h"
|
||||
#include "qt/utility/QtDeviceScaledPixmap.h"
|
||||
|
||||
QtGraphNodeAccess::QtAccessArrow::QtAccessArrow(QGraphicsItem* parent)
|
||||
QtGraphNodeAccess::QtAccessToggle::QtAccessToggle(bool expanded, int invisibleSubNodeCount, QGraphicsItem* parent)
|
||||
: QGraphicsRectItem(parent)
|
||||
{
|
||||
const int iconHeight = 4;
|
||||
m_icon = new QGraphicsPixmapItem(this);
|
||||
|
||||
QFont font;
|
||||
font.setFamily("Myriad Pro");
|
||||
font.setWeight(QFont::Normal);
|
||||
font.setPointSize(9);
|
||||
|
||||
m_number = new QGraphicsSimpleTextItem(this);
|
||||
m_number->setFont(font);
|
||||
}
|
||||
|
||||
QtGraphNodeAccess::QtAccessArrow::~QtAccessArrow()
|
||||
{
|
||||
}
|
||||
|
||||
int QtGraphNodeAccess::QtAccessArrow::update(bool visible, int number)
|
||||
{
|
||||
const int iconHeight = 4;
|
||||
|
||||
int spacing = 0;
|
||||
|
||||
if (!visible)
|
||||
if (!expanded && !invisibleSubNodeCount)
|
||||
{
|
||||
m_icon->hide();
|
||||
m_number->hide();
|
||||
return spacing;
|
||||
}
|
||||
|
||||
m_icon->show();
|
||||
|
||||
QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/arrow.png");
|
||||
pixmap.scaleToHeight(iconHeight);
|
||||
|
||||
if (number)
|
||||
{
|
||||
m_number->show();
|
||||
spacing = 13;
|
||||
|
||||
QString numberStr = QString::number(number);
|
||||
m_number->setText(numberStr);
|
||||
m_number->setPos(
|
||||
-QFontMetrics(m_number->font()).width(numberStr) / 2,
|
||||
-iconHeight - QFontMetrics(m_number->font()).height()
|
||||
);
|
||||
this->hide();
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_number->hide();
|
||||
spacing = 5;
|
||||
QtDeviceScaledPixmap pixmap("data/gui/graph_view/images/arrow.png");
|
||||
pixmap.scaleToHeight(iconHeight);
|
||||
|
||||
pixmap.mirror();
|
||||
if (invisibleSubNodeCount)
|
||||
{
|
||||
QFont font;
|
||||
font.setFamily("Myriad Pro");
|
||||
font.setWeight(QFont::Normal);
|
||||
font.setPointSize(9);
|
||||
|
||||
m_number = new QGraphicsSimpleTextItem(this);
|
||||
m_number->setFont(font);
|
||||
|
||||
QString numberStr = QString::number(invisibleSubNodeCount);
|
||||
m_number->setText(numberStr);
|
||||
m_number->setPos(
|
||||
-QFontMetrics(m_number->font()).width(numberStr) / 2,
|
||||
-iconHeight - QFontMetrics(m_number->font()).height()
|
||||
);
|
||||
}
|
||||
else
|
||||
{
|
||||
pixmap.mirror();
|
||||
}
|
||||
|
||||
m_icon->setPixmap(pixmap.pixmap());
|
||||
m_icon->setPos(-pixmap.width() / 2, -iconHeight);
|
||||
}
|
||||
}
|
||||
|
||||
m_icon->setPixmap(pixmap.pixmap());
|
||||
m_icon->setPos(-pixmap.width() / 2, -iconHeight);
|
||||
|
||||
return spacing;
|
||||
QtGraphNodeAccess::QtAccessToggle::~QtAccessToggle()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QtGraphNodeAccess::QtGraphNodeAccess(TokenComponentAccess::AccessType accessType)
|
||||
QtGraphNodeAccess::QtGraphNodeAccess(
|
||||
TokenComponentAccess::AccessType accessType, bool expanded, int invisibleSubNodeCount
|
||||
)
|
||||
: QtGraphNode()
|
||||
, m_contentHidden(false)
|
||||
, m_access(accessType)
|
||||
, m_accessIconSize(20)
|
||||
{
|
||||
m_padding = Vec4i(10, 10, 10, 10);
|
||||
m_spacing = 8;
|
||||
Vec2i padding(10, 10);
|
||||
|
||||
QFont font;
|
||||
font.setFamily("Myriad Pro");
|
||||
@@ -84,7 +72,7 @@ QtGraphNodeAccess::QtGraphNodeAccess(TokenComponentAccess::AccessType accessType
|
||||
font.setPointSize(11);
|
||||
font.setCapitalization(QFont::AllUppercase);
|
||||
m_text->setFont(font);
|
||||
m_text->setPos(m_padding.x + m_accessIconSize + 3, m_padding.y + m_accessIconSize / 2 - 1);
|
||||
m_text->setPos(padding.x + m_accessIconSize + 3, padding.y + m_accessIconSize / 2 - 1);
|
||||
|
||||
m_rect->setPen(QPen(Qt::transparent));
|
||||
m_rect->setBrush(QBrush(Qt::white));
|
||||
@@ -92,93 +80,41 @@ QtGraphNodeAccess::QtGraphNodeAccess(TokenComponentAccess::AccessType accessType
|
||||
|
||||
std::string accessString = TokenComponentAccess::getAccessString(accessType);
|
||||
this->setName(accessString);
|
||||
m_text->hide();
|
||||
|
||||
QtDeviceScaledPixmap pixmap(QString::fromStdString("data/gui/graph_view/images/" + accessString + ".png"));
|
||||
pixmap.scaleToHeight(m_accessIconSize);
|
||||
|
||||
m_accessIcon = new QGraphicsPixmapItem(pixmap.pixmap(), this);
|
||||
m_accessIcon->setPos(m_padding.x, m_padding.y);
|
||||
m_accessIcon->setPos(padding.x, padding.y);
|
||||
|
||||
m_arrow = new QtAccessArrow(this);
|
||||
m_accessToggle = new QtAccessToggle(expanded, invisibleSubNodeCount, this);
|
||||
}
|
||||
|
||||
QtGraphNodeAccess::~QtGraphNodeAccess()
|
||||
{
|
||||
}
|
||||
|
||||
void QtGraphNodeAccess::hideContent()
|
||||
void QtGraphNodeAccess::setSize(const Vec2i& size)
|
||||
{
|
||||
m_contentHidden = true;
|
||||
QtGraphNode::setSize(size);
|
||||
|
||||
QtGraphNode::hideContent();
|
||||
m_accessToggle->setPos(m_rect->rect().width() / 2, m_rect->rect().height() - 5);
|
||||
}
|
||||
|
||||
void QtGraphNodeAccess::showContent()
|
||||
void QtGraphNodeAccess::addSubNode(const std::shared_ptr<QtGraphNode>& node)
|
||||
{
|
||||
for (std::shared_ptr<QtGraphNode> node : m_subNodes)
|
||||
{
|
||||
node->show();
|
||||
}
|
||||
QtGraphNode::addSubNode(node);
|
||||
|
||||
m_contentHidden = false;
|
||||
m_text->show();
|
||||
}
|
||||
|
||||
void QtGraphNodeAccess::onClick()
|
||||
{
|
||||
if (m_contentHidden)
|
||||
{
|
||||
showContent();
|
||||
}
|
||||
else
|
||||
{
|
||||
hideContent();
|
||||
}
|
||||
QtGraphNode* parent = getParent();
|
||||
|
||||
onSizeChanged();
|
||||
}
|
||||
|
||||
void QtGraphNodeAccess::rebuildLayout()
|
||||
{
|
||||
bool allActive = true;
|
||||
int visibleSubNodes = 0;
|
||||
for (const std::shared_ptr<QtGraphNode>& node : m_subNodes)
|
||||
if (m_accessToggle->isVisible() && parent && parent->getData())
|
||||
{
|
||||
if (!node->getEdgeAndActiveCountRecursive())
|
||||
{
|
||||
allActive = false;
|
||||
}
|
||||
|
||||
if (node->isVisible())
|
||||
{
|
||||
visibleSubNodes++;
|
||||
}
|
||||
MessageGraphNodeExpand(parent->getData()->getId(), m_access).dispatch();
|
||||
}
|
||||
|
||||
int width = m_padding.x + m_accessIconSize;
|
||||
int height = m_padding.y + m_accessIconSize;
|
||||
|
||||
int arrowSpace = m_arrow->update(!allActive, m_subNodes.size() - visibleSubNodes);
|
||||
|
||||
if (visibleSubNodes)
|
||||
{
|
||||
m_text->show();
|
||||
width += QFontMetrics(m_text->font()).width(m_text->text()) + 3;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_text->hide();
|
||||
arrowSpace -= 3;
|
||||
}
|
||||
|
||||
m_padding.w = 10 + arrowSpace;
|
||||
|
||||
width += m_padding.z;
|
||||
height += m_padding.w;
|
||||
|
||||
m_baseSize.x = width;
|
||||
m_baseSize.y = height;
|
||||
|
||||
QtGraphNode::rebuildLayout();
|
||||
|
||||
m_arrow->setPos(m_currentSize.x / 2, m_currentSize.y - 5);
|
||||
}
|
||||
|
||||
@@ -8,14 +8,12 @@ class QtGraphNodeAccess
|
||||
: public QtGraphNode
|
||||
{
|
||||
public:
|
||||
class QtAccessArrow
|
||||
class QtAccessToggle
|
||||
: public QGraphicsRectItem
|
||||
{
|
||||
public:
|
||||
QtAccessArrow(QGraphicsItem* parent);
|
||||
virtual ~QtAccessArrow();
|
||||
|
||||
int update(bool visible, int number);
|
||||
QtAccessToggle(bool expanded, int invisibleSubNodeCount, QGraphicsItem* parent);
|
||||
virtual ~QtAccessToggle();
|
||||
|
||||
private:
|
||||
QGraphicsPixmapItem* m_icon;
|
||||
@@ -23,23 +21,22 @@ public:
|
||||
};
|
||||
|
||||
|
||||
QtGraphNodeAccess(TokenComponentAccess::AccessType accessType);
|
||||
QtGraphNodeAccess(TokenComponentAccess::AccessType accessType, bool expanded, int invisibleSubNodeCount);
|
||||
virtual ~QtGraphNodeAccess();
|
||||
|
||||
virtual void hideContent();
|
||||
virtual void showContent();
|
||||
virtual void setSize(const Vec2i& size);
|
||||
|
||||
virtual void addSubNode(const std::shared_ptr<QtGraphNode>& node);
|
||||
|
||||
virtual void onClick();
|
||||
|
||||
virtual void rebuildLayout();
|
||||
|
||||
private:
|
||||
bool m_contentHidden;
|
||||
TokenComponentAccess::AccessType m_access;
|
||||
|
||||
QGraphicsPixmapItem* m_accessIcon;
|
||||
int m_accessIconSize;
|
||||
|
||||
QtAccessArrow* m_arrow;
|
||||
QtAccessToggle* m_accessToggle;
|
||||
};
|
||||
|
||||
#endif // QT_GRAPH_NODE_ACCESS_H
|
||||
|
||||
@@ -31,7 +31,7 @@ void QtGraphNodeComponentMoveable::nodeMouseMoveEvent(QGraphicsSceneMouseEvent*
|
||||
std::shared_ptr<GraphNode> node = m_graphNode.lock();
|
||||
if (node != NULL)
|
||||
{
|
||||
node->setPosition(Vec2i(event->scenePos().x() - m_mouseOffset.x, event->scenePos().y() - m_mouseOffset.y));
|
||||
node->moveTo(Vec2i(event->scenePos().x() - m_mouseOffset.x, event->scenePos().y() - m_mouseOffset.y));
|
||||
event->accept();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,6 +193,8 @@ add_files(
|
||||
utility/messaging/type/MessageActivateToken.h
|
||||
utility/messaging/type/MessageFind.h
|
||||
utility/messaging/type/MessageFinishedParsing.h
|
||||
utility/messaging/type/MessageGraphNodeExpand.h
|
||||
utility/messaging/type/MessageGraphNodeMove.h
|
||||
utility/messaging/type/MessageLoadProject.h
|
||||
utility/messaging/type/MessageLoadSource.h
|
||||
utility/messaging/type/MessageRefresh.h
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
|
||||
protected:
|
||||
template <typename ViewType>
|
||||
ViewType* getView();
|
||||
ViewType* getView() const;
|
||||
|
||||
private:
|
||||
Component* m_component;
|
||||
@@ -22,7 +22,7 @@ private:
|
||||
|
||||
|
||||
template <typename ViewType>
|
||||
ViewType* Controller::getView()
|
||||
ViewType* Controller::getView() const
|
||||
{
|
||||
if (m_component)
|
||||
return m_component->getView<ViewType>();
|
||||
|
||||
@@ -9,6 +9,19 @@
|
||||
#include "component/view/GraphView.h"
|
||||
#include "data/access/GraphAccess.h"
|
||||
|
||||
GraphController::Margins::Margins()
|
||||
: left(0)
|
||||
, right(0)
|
||||
, top(0)
|
||||
, bottom(0)
|
||||
, betweenX(0)
|
||||
, betweenY(0)
|
||||
, minWidth(0)
|
||||
, charWidth(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
GraphController::GraphController(GraphAccess* graphAccess)
|
||||
: m_graphAccess(graphAccess)
|
||||
{
|
||||
@@ -29,7 +42,30 @@ void GraphController::handleMessage(MessageActivateTokens* message)
|
||||
createDummyGraphForTokenIds(message->tokenIds);
|
||||
}
|
||||
|
||||
GraphView* GraphController::getView()
|
||||
void GraphController::handleMessage(MessageGraphNodeExpand* message)
|
||||
{
|
||||
DummyNode* node = findDummyNodeAccessRecursive(m_dummyNodes, message->tokenId, message->access);
|
||||
if (node)
|
||||
{
|
||||
node->expanded = !node->expanded;
|
||||
|
||||
setActiveAndVisibility(m_activeTokenIds);
|
||||
layoutNesting();
|
||||
|
||||
getView()->rebuildGraph(nullptr, m_dummyNodes, m_dummyEdges);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphController::handleMessage(MessageGraphNodeMove* message)
|
||||
{
|
||||
DummyNode* node = findDummyNodeRecursive(m_dummyNodes, message->tokenId);
|
||||
if (node)
|
||||
{
|
||||
node->position = message->position;
|
||||
}
|
||||
}
|
||||
|
||||
GraphView* GraphController::getView() const
|
||||
{
|
||||
return Controller::getView<GraphView>();
|
||||
}
|
||||
@@ -47,12 +83,14 @@ void GraphController::createDummyGraphForTokenIds(const std::vector<Id>& tokenId
|
||||
|
||||
std::shared_ptr<Graph> graph = m_graphAccess->getGraphForActiveTokenIds(tokenIds);
|
||||
|
||||
std::vector<DummyNode> dummyNodes;
|
||||
std::vector<DummyEdge> dummyEdges;
|
||||
|
||||
m_dummyEdges.clear();
|
||||
|
||||
std::set<Id> addedNodes;
|
||||
std::vector<DummyNode> dummyNodes;
|
||||
|
||||
graph->forEachNode(
|
||||
[&dummyNodes, &dummyEdges, &addedNodes, this](Node* node)
|
||||
[&addedNodes, &dummyNodes, this](Node* node)
|
||||
{
|
||||
Node* parent = node->getLastParentNode();
|
||||
Id id = parent->getId();
|
||||
@@ -62,23 +100,29 @@ void GraphController::createDummyGraphForTokenIds(const std::vector<Id>& tokenId
|
||||
}
|
||||
addedNodes.insert(id);
|
||||
|
||||
dummyNodes.push_back(createDummyNodeTopDown(parent, &dummyEdges));
|
||||
dummyNodes.push_back(createDummyNodeTopDown(parent));
|
||||
}
|
||||
);
|
||||
|
||||
layoutFunction(dummyNodes);
|
||||
m_dummyNodes = dummyNodes;
|
||||
|
||||
view->rebuildGraph(graph, tokenIds, dummyNodes, dummyEdges);
|
||||
m_activeTokenIds = tokenIds;
|
||||
setActiveAndVisibility(tokenIds);
|
||||
|
||||
layoutNesting();
|
||||
layoutFunction(m_dummyNodes);
|
||||
|
||||
view->rebuildGraph(graph, m_dummyNodes, m_dummyEdges);
|
||||
}
|
||||
|
||||
DummyNode GraphController::createDummyNodeTopDown(Node* node, std::vector<DummyEdge>* dummyEdges) const
|
||||
DummyNode GraphController::createDummyNodeTopDown(Node* node)
|
||||
{
|
||||
DummyNode result(node);
|
||||
|
||||
node->forEachChildNode(
|
||||
[&result, dummyEdges, this](Node* child)
|
||||
[node, &result, this](Node* child)
|
||||
{
|
||||
DummyNode* container = nullptr;
|
||||
DummyNode* parent = nullptr;
|
||||
|
||||
Edge* edge = child->getMemberEdge();
|
||||
TokenComponentAccess* access = edge->getComponent<TokenComponentAccess>();
|
||||
@@ -90,36 +134,43 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node, std::vector<DummyE
|
||||
{
|
||||
if (dummy.accessType == accessType)
|
||||
{
|
||||
container = &dummy;
|
||||
parent = &dummy;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!container)
|
||||
if (!parent)
|
||||
{
|
||||
result.subNodes.push_back(DummyNode(accessType));
|
||||
container = &result.subNodes.back();
|
||||
}
|
||||
parent = &result.subNodes.back();
|
||||
|
||||
DummyNode* oldParent = findDummyNodeAccessRecursive(m_dummyNodes, node->getId(), accessType);
|
||||
if (oldParent)
|
||||
{
|
||||
parent->expanded = oldParent->expanded;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
container = &result;
|
||||
parent = &result;
|
||||
}
|
||||
|
||||
container->subNodes.push_back(createDummyNodeTopDown(child, dummyEdges));
|
||||
parent->subNodes.push_back(createDummyNodeTopDown(child));
|
||||
}
|
||||
);
|
||||
|
||||
node->forEachEdge(
|
||||
[&result, node, dummyEdges](Edge* edge)
|
||||
[&result, node, this](Edge* edge)
|
||||
{
|
||||
if (edge->isType(Edge::EDGE_MEMBER))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for (const DummyEdge& dummy : *dummyEdges)
|
||||
result.connected = true;
|
||||
|
||||
for (const DummyEdge& dummy : m_dummyEdges)
|
||||
{
|
||||
if (dummy.data->getId() == edge->getId())
|
||||
{
|
||||
@@ -127,9 +178,291 @@ DummyNode GraphController::createDummyNodeTopDown(Node* node, std::vector<DummyE
|
||||
}
|
||||
}
|
||||
|
||||
dummyEdges->push_back(DummyEdge(edge->getFrom()->getId(), edge->getTo()->getId(), edge));
|
||||
m_dummyEdges.push_back(DummyEdge(edge->getFrom()->getId(), edge->getTo()->getId(), edge));
|
||||
}
|
||||
);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void GraphController::setActiveAndVisibility(const std::vector<Id>& activeTokenIds)
|
||||
{
|
||||
for (DummyNode& node : m_dummyNodes)
|
||||
{
|
||||
setNodeActiveAndVisibilityRecursiveBottomUp(node, activeTokenIds);
|
||||
}
|
||||
|
||||
for (DummyEdge& edge : m_dummyEdges)
|
||||
{
|
||||
edge.visible = true;
|
||||
if (find(activeTokenIds.begin(), activeTokenIds.end(), edge.data->getId()) != activeTokenIds.end())
|
||||
{
|
||||
edge.active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool GraphController::setNodeActiveAndVisibilityRecursiveBottomUp(
|
||||
DummyNode& node, const std::vector<Id>& activeTokenIds
|
||||
) const {
|
||||
node.visible = false;
|
||||
node.active = false;
|
||||
|
||||
if (node.data)
|
||||
{
|
||||
node.active = find(activeTokenIds.begin(), activeTokenIds.end(), node.data->getId()) != activeTokenIds.end();
|
||||
}
|
||||
|
||||
bool childVisible = false;
|
||||
for (DummyNode& subNode : node.subNodes)
|
||||
{
|
||||
if (setNodeActiveAndVisibilityRecursiveBottomUp(subNode, activeTokenIds))
|
||||
{
|
||||
childVisible = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.active || node.connected || childVisible)
|
||||
{
|
||||
setNodeVisibilityRecursiveTopDown(node);
|
||||
}
|
||||
|
||||
return node.visible;
|
||||
}
|
||||
|
||||
void GraphController::setNodeVisibilityRecursiveTopDown(DummyNode& node) const
|
||||
{
|
||||
node.visible = true;
|
||||
|
||||
for (DummyNode& subNode : node.subNodes)
|
||||
{
|
||||
if (subNode.accessType != TokenComponentAccess::ACCESS_NONE || node.expanded ||
|
||||
(node.data && node.data->getType() == Node::NODE_ENUM))
|
||||
{
|
||||
setNodeVisibilityRecursiveTopDown(subNode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GraphController::layoutNesting()
|
||||
{
|
||||
if (!m_viewMetrics.width)
|
||||
{
|
||||
m_viewMetrics = getView()->getViewMetrics();
|
||||
}
|
||||
|
||||
for (DummyNode& node : m_dummyNodes)
|
||||
{
|
||||
layoutNestingRecursive(node);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphController::layoutNestingRecursive(DummyNode& node) const
|
||||
{
|
||||
Margins margins = getMarginsForDummyNode(node);
|
||||
|
||||
int y = 0;
|
||||
int x = 0;
|
||||
int width = margins.minWidth;
|
||||
int height = 0;
|
||||
|
||||
if (node.data)
|
||||
{
|
||||
width = margins.charWidth * node.data->getName().size();
|
||||
}
|
||||
|
||||
bool layoutHorizontal = true;
|
||||
for (DummyNode& subNode : node.subNodes)
|
||||
{
|
||||
if (!subNode.visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
layoutNestingRecursive(subNode);
|
||||
|
||||
if (subNode.data || subNode.expanded || subNode.invisibleSubNodeCount != subNode.subNodes.size())
|
||||
{
|
||||
layoutHorizontal = false;
|
||||
}
|
||||
}
|
||||
|
||||
for (DummyNode& subNode : node.subNodes)
|
||||
{
|
||||
if (!subNode.visible)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
subNode.position.x = margins.left + x;
|
||||
subNode.position.y = margins.top + y;
|
||||
|
||||
if (layoutHorizontal)
|
||||
{
|
||||
x += subNode.size.x + margins.betweenX;
|
||||
if (subNode.size.y > height)
|
||||
{
|
||||
height = subNode.size.y;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
y += subNode.size.y + margins.betweenY;
|
||||
if (subNode.size.x > width)
|
||||
{
|
||||
width = subNode.size.x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 0)
|
||||
{
|
||||
x -= margins.betweenX;
|
||||
}
|
||||
if (y > 0)
|
||||
{
|
||||
y -= margins.betweenY;
|
||||
}
|
||||
|
||||
if (layoutHorizontal && x > width)
|
||||
{
|
||||
width = x;
|
||||
}
|
||||
|
||||
node.size.x = margins.left + width + margins.right;
|
||||
node.size.y = margins.top + y + height + margins.bottom;
|
||||
}
|
||||
|
||||
GraphController::Margins GraphController::getMarginsForDummyNode(DummyNode& node) const
|
||||
{
|
||||
Margins margins;
|
||||
margins.betweenX = margins.betweenY = 8;
|
||||
|
||||
if (node.data)
|
||||
{
|
||||
switch (node.data->getType())
|
||||
{
|
||||
case Node::NODE_UNDEFINED:
|
||||
case Node::NODE_NAMESPACE:
|
||||
margins.left = margins.right = 15;
|
||||
margins.top = 28;
|
||||
margins.bottom = 15;
|
||||
|
||||
margins.charWidth = m_viewMetrics.typeNameCharWidth;
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_TYPE:
|
||||
case Node::NODE_STRUCT:
|
||||
case Node::NODE_CLASS:
|
||||
case Node::NODE_ENUM:
|
||||
case Node::NODE_TYPEDEF:
|
||||
if (node.subNodes.size())
|
||||
{
|
||||
margins.left = margins.right = 15;
|
||||
margins.top = 30;
|
||||
margins.bottom = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
margins.left = margins.right = 8;
|
||||
margins.top = margins.bottom = 13;
|
||||
}
|
||||
|
||||
margins.charWidth = m_viewMetrics.typeNameCharWidth;
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_FUNCTION:
|
||||
case Node::NODE_FUNCTION:
|
||||
case Node::NODE_METHOD:
|
||||
margins.left = margins.right = 5;
|
||||
margins.top = margins.bottom = 10;
|
||||
|
||||
margins.charWidth = m_viewMetrics.functionNameCharWidth;
|
||||
break;
|
||||
|
||||
case Node::NODE_UNDEFINED_VARIABLE:
|
||||
case Node::NODE_GLOBAL_VARIABLE:
|
||||
case Node::NODE_FIELD:
|
||||
margins.left = margins.right = 5;
|
||||
margins.top = margins.bottom = 10;
|
||||
|
||||
margins.charWidth = m_viewMetrics.variableNameCharWidth;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node.invisibleSubNodeCount = 0;
|
||||
for (const DummyNode& subNode : node.subNodes)
|
||||
{
|
||||
if (!subNode.visible)
|
||||
{
|
||||
node.invisibleSubNodeCount++;
|
||||
}
|
||||
}
|
||||
|
||||
margins.left = margins.right = 10;
|
||||
margins.top = 40;
|
||||
|
||||
if (node.invisibleSubNodeCount == node.subNodes.size())
|
||||
{
|
||||
margins.minWidth = 20;
|
||||
margins.bottom = 10;
|
||||
}
|
||||
else
|
||||
{
|
||||
margins.minWidth = 82;
|
||||
|
||||
if (node.expanded)
|
||||
{
|
||||
margins.bottom = 15;
|
||||
}
|
||||
else if (node.invisibleSubNodeCount)
|
||||
{
|
||||
margins.bottom = 23;
|
||||
}
|
||||
else
|
||||
{
|
||||
margins.bottom = 10;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return margins;
|
||||
}
|
||||
|
||||
DummyNode* GraphController::findDummyNodeRecursive(std::vector<DummyNode>& nodes, Id tokenId)
|
||||
{
|
||||
for (DummyNode& node : nodes)
|
||||
{
|
||||
if (node.data && node.data->getId() == tokenId)
|
||||
{
|
||||
return &node;
|
||||
}
|
||||
|
||||
DummyNode* result = findDummyNodeRecursive(node.subNodes, tokenId);
|
||||
if (result != nullptr)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
DummyNode* GraphController::findDummyNodeAccessRecursive(
|
||||
std::vector<DummyNode>& nodes, Id parentId, TokenComponentAccess::AccessType type
|
||||
){
|
||||
DummyNode* node = findDummyNodeRecursive(nodes, parentId);
|
||||
if (node)
|
||||
{
|
||||
for (DummyNode& subNode : node->subNodes)
|
||||
{
|
||||
if (subNode.accessType == type)
|
||||
{
|
||||
return &subNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
#include "utility/messaging/MessageListener.h"
|
||||
#include "utility/messaging/type/MessageActivateToken.h"
|
||||
#include "utility/messaging/type/MessageActivateTokens.h"
|
||||
#include "utility/messaging/type/MessageGraphNodeExpand.h"
|
||||
#include "utility/messaging/type/MessageGraphNodeMove.h"
|
||||
|
||||
#include "component/controller/Controller.h"
|
||||
#include "component/controller/GraphLayouter.h"
|
||||
#include "component/view/GraphView.h"
|
||||
|
||||
struct DummyNode;
|
||||
struct DummyEdge;
|
||||
class Graph;
|
||||
class GraphView;
|
||||
class GraphAccess;
|
||||
class Node;
|
||||
|
||||
@@ -21,21 +23,59 @@ class GraphController
|
||||
: public Controller
|
||||
, public MessageListener<MessageActivateToken>
|
||||
, public MessageListener<MessageActivateTokens>
|
||||
, public MessageListener<MessageGraphNodeExpand>
|
||||
, public MessageListener<MessageGraphNodeMove>
|
||||
{
|
||||
public:
|
||||
struct Margins
|
||||
{
|
||||
Margins();
|
||||
|
||||
int left;
|
||||
int right;
|
||||
|
||||
int top;
|
||||
int bottom;
|
||||
|
||||
int betweenX;
|
||||
int betweenY;
|
||||
|
||||
int minWidth;
|
||||
float charWidth;
|
||||
};
|
||||
|
||||
GraphController(GraphAccess* graphAccess);
|
||||
~GraphController();
|
||||
|
||||
private:
|
||||
virtual void handleMessage(MessageActivateToken* message);
|
||||
virtual void handleMessage(MessageActivateTokens* message);
|
||||
virtual void handleMessage(MessageGraphNodeExpand* message);
|
||||
virtual void handleMessage(MessageGraphNodeMove* message);
|
||||
|
||||
GraphView* getView();
|
||||
GraphView* getView() const;
|
||||
|
||||
void createDummyGraphForTokenIds(const std::vector<Id>& tokenIds);
|
||||
DummyNode createDummyNodeTopDown(Node* node, std::vector<DummyEdge>* dummyEdges) const;
|
||||
DummyNode createDummyNodeTopDown(Node* node);
|
||||
|
||||
void setActiveAndVisibility(const std::vector<Id>& activeTokenIds);
|
||||
bool setNodeActiveAndVisibilityRecursiveBottomUp(DummyNode& node, const std::vector<Id>& activeTokenIds) const;
|
||||
void setNodeVisibilityRecursiveTopDown(DummyNode& node) const;
|
||||
|
||||
void layoutNesting();
|
||||
void layoutNestingRecursive(DummyNode& node) const;
|
||||
|
||||
Margins getMarginsForDummyNode(DummyNode& node) const;
|
||||
DummyNode* findDummyNodeRecursive(std::vector<DummyNode>& nodes, Id tokenId);
|
||||
DummyNode* findDummyNodeAccessRecursive(std::vector<DummyNode>& nodes, Id parentId, TokenComponentAccess::AccessType type);
|
||||
|
||||
GraphAccess* m_graphAccess;
|
||||
GraphView::Metrics m_viewMetrics;
|
||||
|
||||
std::vector<DummyNode> m_dummyNodes;
|
||||
std::vector<DummyEdge> m_dummyEdges;
|
||||
|
||||
std::vector<Id> m_activeTokenIds;
|
||||
};
|
||||
|
||||
#endif // GRAPH_CONTROLLER_H
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
#include "component/view/GraphView.h"
|
||||
|
||||
GraphView::Metrics::Metrics()
|
||||
: width(0)
|
||||
, height(0)
|
||||
, typeNameCharWidth(0.0f)
|
||||
, variableNameCharWidth(0.0f)
|
||||
, functionNameCharWidth(0.0f)
|
||||
{
|
||||
}
|
||||
|
||||
GraphView::GraphView(ViewLayout* viewLayout)
|
||||
: View(viewLayout, Vec2i(100, 100))
|
||||
{
|
||||
|
||||
@@ -15,18 +15,28 @@ class Graph;
|
||||
class GraphView : public View
|
||||
{
|
||||
public:
|
||||
struct Metrics
|
||||
{
|
||||
Metrics();
|
||||
|
||||
int width;
|
||||
int height;
|
||||
|
||||
float typeNameCharWidth;
|
||||
float variableNameCharWidth;
|
||||
float functionNameCharWidth;
|
||||
};
|
||||
|
||||
GraphView(ViewLayout* viewLayout);
|
||||
virtual ~GraphView();
|
||||
|
||||
virtual std::string getName() const;
|
||||
|
||||
virtual void rebuildGraph(
|
||||
std::shared_ptr<Graph> graph,
|
||||
std::vector<Id> activeTokenIds,
|
||||
const std::vector<DummyNode>& nodes,
|
||||
const std::vector<DummyEdge>& edges) = 0;
|
||||
|
||||
std::shared_ptr<Graph> graph, const std::vector<DummyNode>& nodes, const std::vector<DummyEdge>& edges) = 0;
|
||||
virtual void clear() = 0;
|
||||
|
||||
virtual Metrics getViewMetrics() const = 0;
|
||||
};
|
||||
|
||||
#endif // GRAPH_VIEW_H
|
||||
@@ -33,6 +33,8 @@ struct DummyEdge
|
||||
: ownerId(o)
|
||||
, targetId(t)
|
||||
, data(data)
|
||||
, visible(false)
|
||||
, active(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -40,6 +42,9 @@ struct DummyEdge
|
||||
Id targetId;
|
||||
|
||||
const Edge* data;
|
||||
|
||||
bool visible;
|
||||
bool active;
|
||||
};
|
||||
|
||||
#endif // GRAPH_EDGE_H
|
||||
|
||||
@@ -26,9 +26,12 @@ public:
|
||||
void setData(const Node* data);
|
||||
|
||||
virtual Vec2i getPosition() const = 0;
|
||||
virtual void setPosition(const Vec2i& position) = 0;
|
||||
virtual bool setPosition(const Vec2i& position) = 0;
|
||||
virtual void moveTo(const Vec2i& position) = 0;
|
||||
|
||||
virtual Vec2i getSize() const = 0;
|
||||
virtual void setSize(const Vec2i& size) = 0;
|
||||
|
||||
virtual Vec4i getBoundingRect() const = 0;
|
||||
virtual Vec4i getParentBoundingRect() const = 0;
|
||||
|
||||
@@ -47,19 +50,39 @@ struct DummyNode
|
||||
DummyNode(const Node* data)
|
||||
: data(data)
|
||||
, accessType(TokenComponentAccess::ACCESS_NONE)
|
||||
, active(false)
|
||||
, connected(false)
|
||||
, expanded(false)
|
||||
, invisibleSubNodeCount(0)
|
||||
, visible(false)
|
||||
{
|
||||
}
|
||||
|
||||
DummyNode(TokenComponentAccess::AccessType accessType)
|
||||
: data(nullptr)
|
||||
, accessType(accessType)
|
||||
, active(false)
|
||||
, connected(false)
|
||||
, expanded(false)
|
||||
, invisibleSubNodeCount(0)
|
||||
, visible(false)
|
||||
{
|
||||
}
|
||||
|
||||
const Node* data;
|
||||
const TokenComponentAccess::AccessType accessType;
|
||||
TokenComponentAccess::AccessType accessType;
|
||||
|
||||
Vec2i position;
|
||||
Vec2i size;
|
||||
|
||||
bool active;
|
||||
bool connected;
|
||||
|
||||
bool expanded;
|
||||
size_t invisibleSubNodeCount;
|
||||
|
||||
bool visible;
|
||||
|
||||
std::vector<DummyNode> subNodes;
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef MESSAGE_GRAPH_NODE_EXPAND_H
|
||||
#define MESSAGE_GRAPH_NODE_EXPAND_H
|
||||
|
||||
#include "utility/messaging/Message.h"
|
||||
#include "utility/types.h"
|
||||
#include "data/graph/token_component/TokenComponentAccess.h"
|
||||
|
||||
class MessageGraphNodeExpand: public Message<MessageGraphNodeExpand>
|
||||
{
|
||||
public:
|
||||
MessageGraphNodeExpand(Id tokenId, TokenComponentAccess::AccessType access)
|
||||
: tokenId(tokenId)
|
||||
, access(access)
|
||||
{
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageGraphNodeExpand";
|
||||
}
|
||||
|
||||
const Id tokenId;
|
||||
const TokenComponentAccess::AccessType access;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_GRAPH_NODE_EXPAND_H
|
||||
@@ -0,0 +1,26 @@
|
||||
#ifndef MESSAGE_GRAPH_NODE_MOVE_H
|
||||
#define MESSAGE_GRAPH_NODE_MOVE_H
|
||||
|
||||
#include "utility/math/Vector2.h"
|
||||
#include "utility/messaging/Message.h"
|
||||
#include "utility/types.h"
|
||||
|
||||
class MessageGraphNodeMove: public Message<MessageGraphNodeMove>
|
||||
{
|
||||
public:
|
||||
MessageGraphNodeMove(Id tokenId, Vec2i position)
|
||||
: tokenId(tokenId)
|
||||
, position(position)
|
||||
{
|
||||
}
|
||||
|
||||
static const std::string getStaticType()
|
||||
{
|
||||
return "MessageGraphNodeMove";
|
||||
}
|
||||
|
||||
const Id tokenId;
|
||||
const Vec2i position;
|
||||
};
|
||||
|
||||
#endif // MESSAGE_GRAPH_NODE_MOVE_H
|
||||
Reference in New Issue
Block a user