ui: improved graph view layouting and bundling

* move top and bottom layout buckets closer to center buckets
* split undefined bundles into users and usees
* acknowledge zoom for graph view size in layouting
* bundle all referencing nodes
* fixed bundle node and bundle edge count
This commit is contained in:
Eberhard Graether
2016-02-04 16:15:01 +01:00
parent 5c49eaf293
commit acce0477b4
7 changed files with 216 additions and 22 deletions
+130 -19
View File
@@ -445,14 +445,14 @@ void GraphController::bundleNodes()
"Referenced Types"
);
bundleNodesMatching(
[&](const DummyNode& node)
{
return isTypeNodeWithSingleAggregation(node, TokenComponentAggregation::DIRECTION_FORWARD);
},
3,
"Referencing Types"
);
// bundleNodesMatching(
// [&](const DummyNode& node)
// {
// return isTypeNodeWithSingleAggregation(node, TokenComponentAggregation::DIRECTION_FORWARD);
// },
// 3,
// "Referencing Types"
// );
bundleNodesMatching(
[&](const DummyNode& node)
@@ -473,18 +473,31 @@ void GraphController::bundleNodes()
);
bundleNodesMatching(
[](const DummyNode& node)
[&](const DummyNode& node)
{
if (node.visible && node.isGraphNode() && !node.hasActiveSubNode() && !node.data->isDefined())
{
return true;
}
return false;
return isUndefinedNode(node, false);
},
2,
"Undefined Symbols"
);
bundleNodesMatching(
[&](const DummyNode& node)
{
return isUndefinedNode(node, true);
},
2,
"Undefined Symbols"
);
bundleNodesMatching(
[&](const DummyNode& node)
{
return isTypeUserNode(node);
},
8,
"Referencing Symbols"
);
}
void GraphController::bundleNodesMatching(std::function<bool(const DummyNode&)> matcher, size_t count, const std::string& name)
@@ -518,6 +531,8 @@ void GraphController::bundleNodesMatching(std::function<bool(const DummyNode&)>
node.visible = false;
bundleNode.bundledNodes.push_back(node);
bundleNode.bundledNodeCount += node.getConnectedSubNodeCount();
if (!bundleNode.tokenId)
{
bundleNode.tokenId = node.data->getId();
@@ -527,12 +542,13 @@ void GraphController::bundleNodesMatching(std::function<bool(const DummyNode&)>
}
std::vector<DummyEdge> bundleEdges;
for (DummyNode& node : bundleNode.bundledNodes)
std::vector<const DummyNode*> bundledNodes = bundleNode.getAllBundledNodes();
for (const DummyNode* node : bundledNodes)
{
for (DummyEdge& edge : m_dummyEdges)
{
bool owner = (edge.ownerId == node.data->getId());
bool target = (edge.targetId == node.data->getId());
bool owner = (edge.ownerId == node->data->getId());
bool target = (edge.targetId == node->data->getId());
if (!owner && !target)
{
@@ -573,7 +589,7 @@ void GraphController::bundleNodesMatching(std::function<bool(const DummyNode&)>
bool GraphController::isTypeNodeWithSingleAggregation(
const DummyNode& node, TokenComponentAggregation::Direction direction
) const {
const Node::NodeTypeMask typeMask = Node::NODE_STRUCT | Node::NODE_CLASS;
const Node::NodeTypeMask typeMask = Node::NODE_STRUCT | Node::NODE_CLASS | Node::NODE_TYPEDEF;
if (!node.visible || !node.isGraphNode() || node.hasVisibleSubNode() || !node.data->isType(typeMask))
{
@@ -639,6 +655,101 @@ bool GraphController::isTypeNodeWithSingleInheritance(const DummyNode& node, boo
return matches;
}
bool GraphController::isUndefinedNode(const DummyNode& node, bool isUsed) const
{
if (!node.visible || node.active || !node.isGraphNode() || node.hasActiveSubNode() || node.data->isDefined())
{
return false;
}
bool matches = true;
Id tokenId = node.data->getId();
node.data->forEachEdge(
[isUsed, tokenId, &matches](Edge* edge)
{
if (edge->isType(Edge::EDGE_MEMBER))
{
return;
}
Id fromId = edge->getFrom()->getId();
Id toId = edge->getTo()->getId();
if (edge->isType(Edge::EDGE_AGGREGATION))
{
TokenComponentAggregation::Direction dir = edge->getComponent<TokenComponentAggregation>()->getDirection();
switch (dir)
{
case TokenComponentAggregation::DIRECTION_BACKWARD:
{
Id id = fromId;
fromId = toId;
toId = id;
}
break;
case TokenComponentAggregation::DIRECTION_NONE:
matches = false;
return;
default:
break;
}
}
if ((!isUsed && toId == tokenId) ||
(isUsed && fromId == tokenId))
{
matches = false;
}
}
);
return matches;
}
bool GraphController::isTypeUserNode(const DummyNode& node) const
{
if (!node.visible || node.active || !node.isGraphNode() || node.hasActiveSubNode())
{
return false;
}
std::vector<const Node*> nodes;
nodes.push_back(node.data);
node.data->forEachChildNodeRecursive(
[&nodes](Node* n)
{
nodes.push_back(n);
}
);
bool matches = true;
for (const Node* n : nodes)
{
Id tokenId = n->getId();
n->forEachEdge(
[tokenId, &matches](Edge* edge)
{
if (edge->isType(Edge::EDGE_MEMBER | Edge::EDGE_AGGREGATION))
{
return;
}
if (!edge->isType(Edge::EDGE_TYPE_USAGE | Edge::EDGE_TYPE_OF | Edge::EDGE_TEMPLATE_ARGUMENT | Edge::EDGE_TYPEDEF_OF) ||
edge->getFrom()->getId() != tokenId)
{
matches = false;
}
}
);
}
return matches;
}
#define BUNDLE_BY_TYPE(__type__, __name__) \
bundleNodesMatching( \
[&](const DummyNode& node) \
@@ -70,6 +70,8 @@ private:
void bundleNodesMatching(std::function<bool(const DummyNode&)> matcher, size_t count, const std::string& name);
bool isTypeNodeWithSingleAggregation(const DummyNode& node, TokenComponentAggregation::Direction direction) const;
bool isTypeNodeWithSingleInheritance(const DummyNode& node, bool isBase) const;
bool isUndefinedNode(const DummyNode& node, bool isUsed) const;
bool isTypeUserNode(const DummyNode& node) const;
void bundleNodesByType();
void layoutNesting();
@@ -224,8 +224,15 @@ void BucketGrid::layoutBuckets()
{
Bucket* bucket = &m_buckets[j][i];
bucket->layout(x, y, widths[i], heights[j]);
int yOff = 0;
// move buckets over or below the middle one closer
if (i == 0 && (j == -1 || j == 1))
{
Bucket* midBucket = &m_buckets[0][0];
yOff = (heights[0] - midBucket->getHeight()) / 2 * -j;
}
bucket->layout(x, y + yOff, widths[i], heights[j]);
x += widths[i] + GraphViewStyle::toGridGap(85);
}
@@ -3,6 +3,7 @@
#include "utility/math/Vector2.h"
#include "utility/types.h"
#include "utility/utility.h"
#include "data/graph/token_component/TokenComponentAccess.h"
@@ -24,6 +25,7 @@ public:
, hasParent(true)
, accessType(TokenComponentAccess::ACCESS_NONE)
, invisibleSubNodeCount(0)
, bundledNodeCount(0)
{
}
@@ -101,6 +103,60 @@ public:
return false;
}
size_t getConnectedSubNodeCount() const
{
size_t count = 0;
if (connected)
{
count += 1;
}
for (const DummyNode& node : subNodes)
{
count += node.getConnectedSubNodeCount();
}
return count;
}
std::vector<const DummyNode*> getConnectedSubNodes() const
{
std::vector<const DummyNode*> nodes;
if (connected)
{
nodes.push_back(this);
}
for (const DummyNode& node : subNodes)
{
utility::append(nodes, node.getConnectedSubNodes());
}
return nodes;
}
std::vector<const DummyNode*> getAllBundledNodes() const
{
std::vector<const DummyNode*> nodes;
for (const DummyNode& node : bundledNodes)
{
utility::append(nodes, node.getConnectedSubNodes());
}
return nodes;
}
size_t getBundledNodeCount() const
{
if (bundledNodeCount > 0)
{
return bundledNodeCount;
}
return bundledNodes.size();
}
Vec2i position;
Vec2i size;
@@ -129,6 +185,7 @@ public:
// BundleNode
std::vector<DummyNode> bundledNodes;
size_t bundledNodeCount;
};
#endif // DUMMY_NODE_H
+14
View File
@@ -287,6 +287,20 @@ void Node::forEachChildNode(std::function<void(Node*)> func) const
);
}
void Node::forEachChildNodeRecursive(std::function<void(Node*)> func) const
{
forEachEdgeOfType(Edge::EDGE_MEMBER,
[func, this](Edge* e)
{
if (this != e->getTo())
{
func(e->getTo());
e->getTo()->forEachChildNode(func);
}
}
);
}
bool Node::hasReferences() const
{
if (getLocationIds().size() > 0)
+1
View File
@@ -80,6 +80,7 @@ public:
void forEachEdge(std::function<void(Edge*)> func) const;
void forEachEdgeOfType(Edge::EdgeTypeMask mask, std::function<void(Edge*)> func) const;
void forEachChildNode(std::function<void(Node*)> func) const;
void forEachChildNodeRecursive(std::function<void(Node*)> func) const;
bool hasReferences() const;
+4 -2
View File
@@ -126,7 +126,9 @@ void QtGraphView::resizeView()
Vec2i QtGraphView::getViewSize() const
{
QGraphicsView* view = getView();
return Vec2i(view->width(), view->height());
float zoomFactor = GraphViewStyle::getZoomFactor();
return Vec2i(view->width() / zoomFactor - 80, view->height() / zoomFactor - 80);
}
void QtGraphView::centerScrollBars()
@@ -337,7 +339,7 @@ std::shared_ptr<QtGraphNode> QtGraphView::createNodeRecursive(
}
else if (node.isBundleNode())
{
newNode = std::make_shared<QtGraphNodeBundle>(node.tokenId, node.bundledNodes.size(), node.name);
newNode = std::make_shared<QtGraphNodeBundle>(node.tokenId, node.getBundledNodeCount(), node.name);
}
newNode->setPosition(node.position);