ui: Improvements and fixes in graph layouting
* put nodes with bidirectional aggregations on the left * layout aggregations either horizontal or vertical based on buckets * exceed bucket height if only one element and vertical split * fixed hiding nodes in sublayout showed empty spot
This commit is contained in:
@@ -1493,7 +1493,6 @@ void GraphController::groupNodesByParents(GroupType groupType)
|
||||
m_dummyNodes.push_back(groupNode);
|
||||
}
|
||||
|
||||
std::vector<DummyNode::BundleInfo> bundleInfos;
|
||||
for (std::shared_ptr<DummyNode> dummyNode : p.second)
|
||||
{
|
||||
if (dummyNode->hasActiveSubNode())
|
||||
@@ -1501,10 +1500,6 @@ void GraphController::groupNodesByParents(GroupType groupType)
|
||||
groupNode->bundleInfo = dummyNode->bundleInfo;
|
||||
groupNode->bundleId = dummyNode->bundleId;
|
||||
}
|
||||
else
|
||||
{
|
||||
bundleInfos.push_back(dummyNode->bundleInfo);
|
||||
}
|
||||
|
||||
groupNode->subNodes.push_back(dummyNode);
|
||||
m_topLevelAncestorIds[dummyNode->tokenId] = groupNode->tokenId;
|
||||
@@ -1514,9 +1509,9 @@ void GraphController::groupNodesByParents(GroupType groupType)
|
||||
if (!groupNode->bundleId)
|
||||
{
|
||||
groupNode->bundleId = groupNode->subNodes[0]->bundleId;
|
||||
groupNode->bundleInfo = DummyNode::BundleInfo::averageBundleInfo(bundleInfos);
|
||||
}
|
||||
|
||||
groupNode->bundleInfo = DummyNode::BundleInfo::averageBundleInfo(groupNode->getBundleInfos());
|
||||
groupNode->sortSubNodesByName();
|
||||
}
|
||||
|
||||
|
||||
@@ -71,18 +71,29 @@ void Bucket::preLayout(Vec2i viewSize, bool addVerticalSplit, bool forceVertical
|
||||
std::vector<std::vector<DummyNode*>> nodesInCol;
|
||||
nodesInCol.push_back({ });
|
||||
|
||||
int heightDiff = 0;
|
||||
for (const std::shared_ptr<DummyNode>& node : m_nodes)
|
||||
{
|
||||
if (y > height)
|
||||
if (y > height + heightDiff)
|
||||
{
|
||||
colHeights.push_back(y - GraphViewStyle::s_gridCellPadding);
|
||||
colWidths.push_back(width);
|
||||
// keep adding to the same columns if it only contains 1 element, which will end up above the middle split
|
||||
if (nodesInCol.back().size() == 1 && m_nodes.size() > 1 && addVerticalSplit | forceVerticalSplit)
|
||||
{
|
||||
heightDiff = y;
|
||||
}
|
||||
else
|
||||
{
|
||||
colHeights.push_back(y - GraphViewStyle::s_gridCellPadding);
|
||||
colWidths.push_back(width);
|
||||
|
||||
y = 0;
|
||||
x += GraphViewStyle::toGridOffset(width + 45);
|
||||
width = 0;
|
||||
y = 0;
|
||||
x += GraphViewStyle::toGridOffset(width + 45);
|
||||
width = 0;
|
||||
|
||||
nodesInCol.push_back({ });
|
||||
nodesInCol.push_back({ });
|
||||
|
||||
heightDiff = 0;
|
||||
}
|
||||
}
|
||||
|
||||
node->position.x = x;
|
||||
@@ -92,8 +103,8 @@ void Bucket::preLayout(Vec2i viewSize, bool addVerticalSplit, bool forceVertical
|
||||
|
||||
y += GraphViewStyle::toGridSize(node->size.y) + GraphViewStyle::s_gridCellPadding;
|
||||
|
||||
width = (node->size.x > width ? node->size.x : width);
|
||||
m_height = (y > m_height ? y : m_height);
|
||||
width = std::max(width, node->size.x());
|
||||
m_height = std::max(m_height, y);
|
||||
}
|
||||
|
||||
colHeights.push_back(y - GraphViewStyle::s_gridCellPadding);
|
||||
@@ -242,28 +253,16 @@ void BucketLayouter::createBuckets(
|
||||
addNode(nodes[0]);
|
||||
}
|
||||
|
||||
std::vector<const DummyEdge*> remainingEdges;
|
||||
for (const std::shared_ptr<DummyEdge>& edge : edges)
|
||||
for (std::shared_ptr<DummyEdge> edge : edges)
|
||||
{
|
||||
remainingEdges.push_back(edge.get());
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
while (remainingEdges.size())
|
||||
{
|
||||
const DummyEdge* edge = remainingEdges[i];
|
||||
|
||||
std::shared_ptr<DummyNode> owner = findTopMostDummyNodeRecursive(nodes, edge->ownerId, nullptr);
|
||||
std::shared_ptr<DummyNode> target = findTopMostDummyNodeRecursive(nodes, edge->targetId, nullptr);
|
||||
|
||||
bool removeEdge = false;
|
||||
if (!owner || !target || owner == target)
|
||||
bool horizontal = true;
|
||||
|
||||
if (owner && target && owner != target && owner->getsLayouted() && target->getsLayouted())
|
||||
{
|
||||
removeEdge = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
bool horizontal = !owner->bundleInfo.layoutVertical && !target->bundleInfo.layoutVertical;
|
||||
horizontal = !owner->bundleInfo.layoutVertical && !target->bundleInfo.layoutVertical;
|
||||
|
||||
if (!horizontal)
|
||||
{
|
||||
@@ -273,27 +272,18 @@ void BucketLayouter::createBuckets(
|
||||
std::swap(owner, target);
|
||||
}
|
||||
}
|
||||
else if (edge->getDirection() == TokenComponentAggregation::DIRECTION_BACKWARD)
|
||||
else if (edge->getDirection() == TokenComponentAggregation::DIRECTION_BACKWARD ||
|
||||
// put nodes with bidirectional edges on the left
|
||||
(edge->getDirection() == TokenComponentAggregation::DIRECTION_NONE &&
|
||||
!target->bundleInfo.isReferencing && !target->bundleInfo.isReferenced))
|
||||
{
|
||||
std::swap(owner, target);
|
||||
}
|
||||
|
||||
removeEdge = addNode(owner, target, horizontal);
|
||||
horizontal = addNode(owner, target, horizontal);
|
||||
}
|
||||
|
||||
if (removeEdge)
|
||||
{
|
||||
remainingEdges.erase(remainingEdges.begin() + i);
|
||||
}
|
||||
else
|
||||
{
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == remainingEdges.size())
|
||||
{
|
||||
i = 0;
|
||||
}
|
||||
edge->layoutHorizontal = horizontal;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -416,7 +406,7 @@ bool BucketLayouter::addNode(std::shared_ptr<DummyNode> owner, std::shared_ptr<D
|
||||
}
|
||||
else if (ownerBucket && targetBucket)
|
||||
{
|
||||
return true;
|
||||
return ownerBucket->j == targetBucket->j;
|
||||
}
|
||||
|
||||
if (ownerBucket)
|
||||
@@ -436,7 +426,7 @@ bool BucketLayouter::addNode(std::shared_ptr<DummyNode> owner, std::shared_ptr<D
|
||||
bucket->addNode(owner);
|
||||
}
|
||||
|
||||
return true;
|
||||
return horizontal;
|
||||
}
|
||||
|
||||
Bucket* BucketLayouter::getBucket(int i, int j)
|
||||
|
||||
@@ -19,6 +19,7 @@ struct DummyEdge
|
||||
, visible(false)
|
||||
, hidden(false)
|
||||
, active(false)
|
||||
, layoutHorizontal(true)
|
||||
, weight(0)
|
||||
, direction(TokenComponentAggregation::DIRECTION_INVALID)
|
||||
{
|
||||
@@ -31,6 +32,7 @@ struct DummyEdge
|
||||
, visible(false)
|
||||
, hidden(false)
|
||||
, active(false)
|
||||
, layoutHorizontal(true)
|
||||
, weight(0)
|
||||
, direction(TokenComponentAggregation::DIRECTION_INVALID)
|
||||
{
|
||||
@@ -92,6 +94,8 @@ struct DummyEdge
|
||||
|
||||
std::vector<Vec4i> path;
|
||||
|
||||
bool layoutHorizontal;
|
||||
|
||||
// BundleEdge
|
||||
int weight;
|
||||
TokenComponentAggregation::Direction direction;
|
||||
|
||||
@@ -74,11 +74,11 @@ public:
|
||||
}
|
||||
|
||||
BundleInfo info;
|
||||
if (activeCount > bundleInfos.size() / 2) info.isActive = true;
|
||||
if (definedCount > bundleInfos.size() / 2) info.isDefined = true;
|
||||
if (verticalLayoutCount > bundleInfos.size() / 2) info.layoutVertical = true;
|
||||
if (referencedCount > bundleInfos.size() / 2) info.isReferenced = true;
|
||||
if (referencingCount > bundleInfos.size() / 2) info.isReferencing = true;
|
||||
if (activeCount >= std::ceil(bundleInfos.size() / 2.0f)) info.isActive = true;
|
||||
if (definedCount >= std::ceil(bundleInfos.size() / 2.0f)) info.isDefined = true;
|
||||
if (verticalLayoutCount >= std::ceil(bundleInfos.size() / 2.0f)) info.layoutVertical = true;
|
||||
if (referencedCount >= std::ceil(bundleInfos.size() / 2.0f)) info.isReferenced = true;
|
||||
if (referencingCount >= std::ceil(bundleInfos.size() / 2.0f)) info.isReferencing = true;
|
||||
return info;
|
||||
}
|
||||
|
||||
@@ -431,6 +431,16 @@ public:
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::vector<BundleInfo> getBundleInfos() const
|
||||
{
|
||||
std::vector<BundleInfo> bundleInfos;
|
||||
for (const std::shared_ptr<DummyNode>& subNode : subNodes)
|
||||
{
|
||||
bundleInfos.push_back(subNode->bundleInfo);
|
||||
}
|
||||
return bundleInfos;
|
||||
}
|
||||
|
||||
Type type;
|
||||
|
||||
Vec2i position;
|
||||
|
||||
@@ -1042,7 +1042,8 @@ QtGraphEdge* QtGraphView::createEdge(
|
||||
if (owner != nullptr && target != nullptr)
|
||||
{
|
||||
QtGraphEdge* qtEdge = new QtGraphEdge(
|
||||
owner, target, edge->data, edge->getWeight(), edge->active && !useBezier, edge->getDirection());
|
||||
owner, target, edge->data, edge->getWeight(), edge->active && !useBezier, edge->layoutHorizontal,
|
||||
edge->getDirection());
|
||||
|
||||
if (trailMode != Graph::TRAIL_NONE)
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@ QtGraphEdge::QtGraphEdge(
|
||||
const Edge* data,
|
||||
size_t weight,
|
||||
bool isActive,
|
||||
bool horizontal,
|
||||
TokenComponentAggregation::Direction direction
|
||||
)
|
||||
: m_data(data)
|
||||
@@ -38,10 +39,10 @@ QtGraphEdge::QtGraphEdge(
|
||||
, m_child(nullptr)
|
||||
, m_isActive(isActive)
|
||||
, m_isFocused(false)
|
||||
, m_isHorizontal(horizontal)
|
||||
, m_weight(weight)
|
||||
, m_direction(direction)
|
||||
, m_isTrailEdge(false)
|
||||
, m_isHorizontalTrail(false)
|
||||
, m_useBezier(false)
|
||||
, m_mousePos(0.0f, 0.0f)
|
||||
, m_mouseMoved(false)
|
||||
@@ -117,6 +118,8 @@ void QtGraphEdge::updateLine()
|
||||
targetParentRect = targetParent->getBoundingRect();
|
||||
}
|
||||
|
||||
QtLineItemBase::Route route = m_isHorizontal ? QtLineItemBase::ROUTE_HORIZONTAL : QtLineItemBase::ROUTE_VERTICAL;
|
||||
|
||||
if (m_useBezier)
|
||||
{
|
||||
for (QGraphicsItem* item : childItems())
|
||||
@@ -128,9 +131,6 @@ void QtGraphEdge::updateLine()
|
||||
style.originOffset.y() = 0;
|
||||
style.targetOffset.y() = 0;
|
||||
|
||||
QtLineItemBase::Route route =
|
||||
m_isHorizontalTrail ? QtLineItemBase::ROUTE_HORIZONTAL : QtLineItemBase::ROUTE_VERTICAL;
|
||||
|
||||
for (const Vec4i& rect : m_path)
|
||||
{
|
||||
QtLineItemBezier* bezier = new QtLineItemBezier(this);
|
||||
@@ -219,7 +219,7 @@ void QtGraphEdge::updateLine()
|
||||
if (type == Edge::EDGE_INHERITANCE || (type == Edge::EDGE_TEMPLATE_SPECIALIZATION &&
|
||||
owner == ownerNonGroupParent && target == targetNonGroupParent))
|
||||
{
|
||||
child->setRoute(QtLineItemBase::ROUTE_VERTICAL);
|
||||
route = QtLineItemBase::ROUTE_VERTICAL;
|
||||
|
||||
if (target->hasActiveChild())
|
||||
{
|
||||
@@ -229,9 +229,11 @@ void QtGraphEdge::updateLine()
|
||||
else if (type != Edge::EDGE_AGGREGATION ||
|
||||
owner != ownerNonGroupParent || target != targetNonGroupParent)
|
||||
{
|
||||
child->setRoute(QtLineItemBase::ROUTE_HORIZONTAL);
|
||||
route = QtLineItemBase::ROUTE_HORIZONTAL;
|
||||
}
|
||||
|
||||
child->setRoute(route);
|
||||
|
||||
bool showArrow = true;
|
||||
if (type == Edge::EDGE_AGGREGATION)
|
||||
{
|
||||
@@ -471,11 +473,11 @@ void QtGraphEdge::setIsTrailEdge(std::vector<Vec4i> path, bool horizontal)
|
||||
m_path = path;
|
||||
m_isTrailEdge = true;
|
||||
m_useBezier = true;
|
||||
m_isHorizontalTrail = horizontal;
|
||||
m_isHorizontal = horizontal;
|
||||
}
|
||||
|
||||
void QtGraphEdge::setUseBezier(bool useBezier)
|
||||
{
|
||||
m_useBezier = useBezier;
|
||||
m_isHorizontalTrail = true;
|
||||
m_isHorizontal = true;
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ public:
|
||||
const Edge* data,
|
||||
size_t weight,
|
||||
bool isActive,
|
||||
bool horizontal,
|
||||
TokenComponentAggregation::Direction direction);
|
||||
virtual ~QtGraphEdge();
|
||||
|
||||
@@ -82,12 +83,12 @@ private:
|
||||
bool m_isActive;
|
||||
bool m_isFocused;
|
||||
|
||||
bool m_isHorizontal;
|
||||
size_t m_weight;
|
||||
|
||||
TokenComponentAggregation::Direction m_direction;
|
||||
|
||||
bool m_isTrailEdge;
|
||||
bool m_isHorizontalTrail;
|
||||
std::vector<Vec4i> m_path;
|
||||
|
||||
bool m_useBezier;
|
||||
|
||||
Reference in New Issue
Block a user