ui: switch Graph to bucket grid layouting
This change introduces bucket grid layouting, which sorts the nodes into buckets based on how they are connected. Each bucket is then layouted individually before they are arranged next to each other. Edges go from left to right, except for inheritance edges that go from bottom to top.
This commit is contained in:
@@ -8,6 +8,8 @@
|
||||
|
||||
QtAngledLineItem::QtAngledLineItem(QGraphicsItem* parent)
|
||||
: QGraphicsLineItem(parent)
|
||||
, m_onBack(false)
|
||||
, m_horizontalIn(false)
|
||||
{
|
||||
this->setAcceptHoverEvents(true);
|
||||
}
|
||||
@@ -38,6 +40,16 @@ void QtAngledLineItem::updateLine(
|
||||
this->setPen(QPen(QBrush(style.color.c_str()), style.width, Qt::SolidLine, Qt::RoundCap));
|
||||
}
|
||||
|
||||
void QtAngledLineItem::setOnBack(bool back)
|
||||
{
|
||||
m_onBack = back;
|
||||
}
|
||||
|
||||
void QtAngledLineItem::setHorizontalIn(bool horizontal)
|
||||
{
|
||||
m_horizontalIn = horizontal;
|
||||
}
|
||||
|
||||
QPainterPath QtAngledLineItem::shape() const
|
||||
{
|
||||
int w = m_style.arrowWidth / 2 + 1;
|
||||
@@ -185,23 +197,31 @@ QPolygon QtAngledLineItem::getPath() const
|
||||
const Vec4i& oR = m_ownerRect;
|
||||
const Vec4i& tR = m_targetRect;
|
||||
|
||||
Vec2f o[2] = { Vec2f(m_ownerParentRect.x, (oR.y + 2 * oR.w) / 3), Vec2f(m_ownerParentRect.z, (oR.y + 2 * oR.w) / 3) };
|
||||
Vec2f t[2] = { Vec2f(m_targetParentRect.x, (2 * tR.y + tR.w) / 3), Vec2f(m_targetParentRect.z, (2 * tR.y + tR.w) / 3) };
|
||||
Vec2f o[2] = { Vec2f(m_ownerParentRect.x, (2 * oR.y + oR.w) / 3), Vec2f(m_ownerParentRect.z, (2 * oR.y + oR.w) / 3) };
|
||||
Vec2f t[2] = { Vec2f(m_targetParentRect.x, (tR.y + 2 * tR.w) / 3), Vec2f(m_targetParentRect.z, (tR.y + 2 * tR.w) / 3) };
|
||||
|
||||
int io = -1;
|
||||
int it = -1;
|
||||
float dist = -1;
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
if (m_onBack)
|
||||
{
|
||||
for (int j = 0; j < 2; j++)
|
||||
io = 1;
|
||||
it = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
Vec2f diff = o[i] - t[j];
|
||||
if (dist < 0 || diff.getLength() < dist)
|
||||
for (int j = 0; j < 2; j++)
|
||||
{
|
||||
dist = diff.getLength();
|
||||
io = i;
|
||||
it = j;
|
||||
Vec2f diff = o[i] - t[j];
|
||||
if (dist < 0 || diff.getLength() < dist)
|
||||
{
|
||||
dist = diff.getLength();
|
||||
io = i;
|
||||
it = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -233,7 +253,11 @@ QPolygon QtAngledLineItem::getPath() const
|
||||
}
|
||||
}
|
||||
|
||||
if (it == io && ((it && tp.x() < op.x()) || (!it && tp.x() > op.x())) )
|
||||
if (it == io && ((it && tp.x() < op.x()) || (!it && tp.x() > op.x())))
|
||||
{
|
||||
tp.setX(op.x());
|
||||
}
|
||||
else if (it != io && m_horizontalIn)
|
||||
{
|
||||
tp.setX(op.x());
|
||||
}
|
||||
@@ -242,10 +266,10 @@ QPolygon QtAngledLineItem::getPath() const
|
||||
op.setX(tp.x());
|
||||
}
|
||||
|
||||
o[0] = Vec2f(oR.x, (oR.y + 2 * oR.w) / 3);
|
||||
o[1] = Vec2f(oR.z, (oR.y + 2 * oR.w) / 3);
|
||||
t[0] = Vec2f(tR.x, (2 * tR.y + tR.w) / 3);
|
||||
t[1] = Vec2f(tR.z, (2 * tR.y + tR.w) / 3);
|
||||
o[0] = Vec2f(oR.x, (2 * oR.y + oR.w) / 3);
|
||||
o[1] = Vec2f(oR.z, (2 * oR.y + oR.w) / 3);
|
||||
t[0] = Vec2f(tR.x, (tR.y + 2 * tR.w) / 3);
|
||||
t[1] = Vec2f(tR.z, (tR.y + 2 * tR.w) / 3);
|
||||
|
||||
if (o[io].y < t[it].y)
|
||||
{
|
||||
|
||||
@@ -19,6 +19,9 @@ public:
|
||||
Vec4i ownerParentRect, Vec4i targetParentRect,
|
||||
GraphViewStyle::EdgeStyle style);
|
||||
|
||||
void setOnBack(bool back);
|
||||
void setHorizontalIn(bool horizontal);
|
||||
|
||||
virtual QPainterPath shape() const;
|
||||
virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem* options, QWidget* widget);
|
||||
|
||||
@@ -33,6 +36,9 @@ private:
|
||||
Vec4i m_targetParentRect;
|
||||
|
||||
GraphViewStyle::EdgeStyle m_style;
|
||||
|
||||
bool m_onBack;
|
||||
bool m_horizontalIn;
|
||||
};
|
||||
|
||||
#endif // QT_ANGLED_LINE_ITEM_H
|
||||
|
||||
@@ -22,11 +22,16 @@ QtGraphEdge::QtGraphEdge(
|
||||
, m_target(target)
|
||||
, m_child(nullptr)
|
||||
, m_isActive(false)
|
||||
, m_fromActive(false)
|
||||
, m_toActive(false)
|
||||
, m_weight(weight)
|
||||
, m_direction(TokenComponentAggregation::DIRECTION_NONE)
|
||||
, m_mousePos(0.0f, 0.0f)
|
||||
, m_mouseMoved(false)
|
||||
{
|
||||
m_fromActive = m_owner.lock()->getIsActive();
|
||||
m_toActive = m_target.lock()->getIsActive();
|
||||
|
||||
this->updateLine();
|
||||
}
|
||||
|
||||
@@ -100,6 +105,16 @@ void QtGraphEdge::updateLine()
|
||||
owner->getBoundingRect(), target->getBoundingRect(),
|
||||
owner->getParentBoundingRect(), target->getParentBoundingRect(),
|
||||
style);
|
||||
|
||||
if (m_fromActive && owner->getLastParent() == target->getLastParent())
|
||||
{
|
||||
dynamic_cast<QtAngledLineItem*>(m_child)->setOnBack(true);
|
||||
}
|
||||
|
||||
if (m_toActive)
|
||||
{
|
||||
dynamic_cast<QtAngledLineItem*>(m_child)->setHorizontalIn(true);
|
||||
}
|
||||
}
|
||||
|
||||
this->setZValue(style.zValue); // Used to draw edges always on top of nodes.
|
||||
@@ -112,9 +127,11 @@ bool QtGraphEdge::getIsActive() const
|
||||
|
||||
void QtGraphEdge::setIsActive(bool isActive)
|
||||
{
|
||||
m_isActive = isActive;
|
||||
|
||||
updateLine();
|
||||
if (m_isActive != isActive)
|
||||
{
|
||||
m_isActive = isActive;
|
||||
updateLine();
|
||||
}
|
||||
}
|
||||
|
||||
void QtGraphEdge::onClick()
|
||||
@@ -138,7 +155,7 @@ void QtGraphEdge::focusIn()
|
||||
|
||||
void QtGraphEdge::focusOut()
|
||||
{
|
||||
this->setIsActive(m_isActive);
|
||||
updateLine();
|
||||
}
|
||||
|
||||
void QtGraphEdge::mousePressEvent(QGraphicsSceneMouseEvent* event)
|
||||
|
||||
@@ -32,6 +32,7 @@ public:
|
||||
|
||||
bool getIsActive() const;
|
||||
void setIsActive(bool isActive);
|
||||
void setFromAndToActive(bool fromActive, bool toActive);
|
||||
|
||||
void onClick();
|
||||
|
||||
@@ -57,6 +58,8 @@ private:
|
||||
QGraphicsLineItem* m_child;
|
||||
|
||||
bool m_isActive;
|
||||
bool m_fromActive;
|
||||
bool m_toActive;
|
||||
size_t m_weight;
|
||||
|
||||
TokenComponentAggregation::Direction m_direction;
|
||||
|
||||
@@ -61,6 +61,21 @@ QtGraphNode* QtGraphNode::getParent() const
|
||||
return m_parentNode.lock().get();
|
||||
}
|
||||
|
||||
QtGraphNode* QtGraphNode::getLastParent() const
|
||||
{
|
||||
QtGraphNode* node = const_cast<QtGraphNode*>(this);
|
||||
while (true)
|
||||
{
|
||||
QtGraphNode* parent = dynamic_cast<QtGraphNode*>(node->parentItem());
|
||||
if (!parent)
|
||||
{
|
||||
break;
|
||||
}
|
||||
node = parent;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
void QtGraphNode::setParent(std::weak_ptr<QtGraphNode> parentNode)
|
||||
{
|
||||
m_parentNode = parentNode;
|
||||
@@ -134,18 +149,7 @@ Vec4i QtGraphNode::getBoundingRect() const
|
||||
|
||||
Vec4i QtGraphNode::getParentBoundingRect() const
|
||||
{
|
||||
const QtGraphNode* node = this;
|
||||
while (true)
|
||||
{
|
||||
const QtGraphNode* parent = dynamic_cast<QtGraphNode*>(node->parentItem());
|
||||
if (!parent)
|
||||
{
|
||||
break;
|
||||
}
|
||||
node = parent;
|
||||
|
||||
}
|
||||
return node->getBoundingRect();
|
||||
return getLastParent()->getBoundingRect();
|
||||
}
|
||||
|
||||
void QtGraphNode::addOutEdge(const std::shared_ptr<QtGraphEdge>& edge)
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
|
||||
#include <QGraphicsItem>
|
||||
|
||||
#include "utility/math/Vector4.h"
|
||||
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
|
||||
class QFont;
|
||||
@@ -33,6 +35,7 @@ public:
|
||||
virtual ~QtGraphNode();
|
||||
|
||||
QtGraphNode* getParent() const;
|
||||
QtGraphNode* getLastParent() const;
|
||||
void setParent(std::weak_ptr<QtGraphNode> parentNode);
|
||||
|
||||
std::list<std::shared_ptr<QtGraphNode>> getSubNodes() const;
|
||||
|
||||
Reference in New Issue
Block a user