ui: Show call graphs, inheritance trees and include trees for active symbol (issue 249 337)
* Added TrailLayouter with Sugiyama dependency layouting * Layouter supports horizontal and vertical layouts * Added basic ui to graph view for showing incoming and outgoing paths * Added depth slider, with infinity at maximum * Disable trail ui when not available * Added trail messages to undo stack and only use last one when undoing * Added QtGraphLineBezier for trail graphs and refactored other line types * Disabled edge activation for trail layouts, shown only visually * Highlight all connected edges when hovering a node in trail layout * Use different color when highlighting call edges for better contrast * Fixed BucketLayouter issue when edge does not leave node * Increased click area for angled edges bug id = 249 337 fortune cookie message = Answer just what the heart prompts to you.
This commit is contained in:
@@ -0,0 +1,181 @@
|
||||
#include "qt/graphics/QtLineItemAngled.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
|
||||
QtLineItemAngled::QtLineItemAngled(QGraphicsItem* parent)
|
||||
: QtLineItemBase(parent)
|
||||
{
|
||||
this->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
|
||||
}
|
||||
|
||||
QtLineItemAngled::~QtLineItemAngled()
|
||||
{
|
||||
}
|
||||
|
||||
QPainterPath QtLineItemAngled::shape() const
|
||||
{
|
||||
QPainterPath path;
|
||||
QPolygon poly = getPath();
|
||||
|
||||
for (int i = 0; i < poly.size() - 1; i++)
|
||||
{
|
||||
path.addRect(QRectF(poly.at(i), poly.at(i + 1)).normalized().adjusted(-5, -5, 5, 5));
|
||||
}
|
||||
|
||||
path.addRect(getArrowBoundingRect(poly).adjusted(-3, -3, 3, 3));
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void QtLineItemAngled::paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget)
|
||||
{
|
||||
painter->setPen(pen());
|
||||
|
||||
QPainterPath path;
|
||||
|
||||
QPolygon poly = getPath();
|
||||
int i = poly.length() - 1;
|
||||
|
||||
path.moveTo(poly.at(i));
|
||||
|
||||
|
||||
// while (i > 0)
|
||||
// {
|
||||
// i--;
|
||||
|
||||
// path.lineTo(poly.at(i));
|
||||
// }
|
||||
// painter->drawPath(path);
|
||||
// return;
|
||||
|
||||
|
||||
QRectF drawRect = options->exposedRect;
|
||||
QRectF partRect;
|
||||
|
||||
int radius = m_style.cornerRadius;
|
||||
int dir = getDirection(poly.at(i), poly.at(i - 1));
|
||||
while (i > 1)
|
||||
{
|
||||
i--;
|
||||
|
||||
QPointF a = poly.at(i);
|
||||
QPointF b = poly.at(i - 1);
|
||||
|
||||
int newDir = getDirection(a, b);
|
||||
int ar = radius;
|
||||
int br = m_style.cornerRadius;
|
||||
|
||||
if (i != 1)
|
||||
{
|
||||
if (dir % 2 == 1 && std::abs(a.y() - b.y()) < 2 * br)
|
||||
{
|
||||
br = std::abs(a.y() - b.y()) / 2;
|
||||
}
|
||||
else if (dir % 2 == 0 && std::abs(a.x() - b.x()) < 2 * br)
|
||||
{
|
||||
br = std::abs(a.x() - b.x()) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case 0: a.setY(a.y() + ar); break;
|
||||
case 1: a.setX(a.x() - ar); break;
|
||||
case 2: a.setY(a.y() - ar); break;
|
||||
case 3: a.setX(a.x() + ar); break;
|
||||
}
|
||||
|
||||
b = poly.at(i);
|
||||
switch (newDir)
|
||||
{
|
||||
case 0: b.setY(b.y() - br); break;
|
||||
case 1: b.setX(b.x() + br); break;
|
||||
case 2: b.setY(b.y() + br); break;
|
||||
case 3: b.setX(b.x() - br); break;
|
||||
}
|
||||
|
||||
partRect = QRectF(poly.at(i + 1), poly.at(i)).adjusted(-1, -1, 1, 1);
|
||||
if (drawRect.intersects(partRect))
|
||||
{
|
||||
path.lineTo(a);
|
||||
}
|
||||
else
|
||||
{
|
||||
path.moveTo(a);
|
||||
}
|
||||
|
||||
partRect = QRectF(a, b).normalized().adjusted(-1, -1, 1, 1);
|
||||
if (drawRect.intersects(partRect))
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case 0:
|
||||
if (newDir == 1)
|
||||
{
|
||||
path.arcTo(a.x(), b.y(), 2 * br, 2 * ar, 180, -90);
|
||||
}
|
||||
else if (newDir == 3)
|
||||
{
|
||||
path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, 90);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (newDir == 0)
|
||||
{
|
||||
path.arcTo(a.x() - ar, b.y() - br, 2 * ar, 2 * br, -90, 90);
|
||||
}
|
||||
else if (newDir == 2)
|
||||
{
|
||||
path.arcTo(a.x() - ar, a.y(), 2 * ar, 2 * br, 90, -90);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (newDir == 1)
|
||||
{
|
||||
path.arcTo(a.x(), a.y() - ar, 2 * br, 2 * ar, 180, 90);
|
||||
}
|
||||
else if (newDir == 3)
|
||||
{
|
||||
path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, -90);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (newDir == 0)
|
||||
{
|
||||
path.arcTo(b.x(), b.y() - br, 2 * ar, 2 * br, -90, -90);
|
||||
}
|
||||
else if (newDir == 2)
|
||||
{
|
||||
path.arcTo(b.x(), a.y(), 2 * ar, 2 * br, 90, 90);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
path.moveTo(b);
|
||||
}
|
||||
|
||||
dir = newDir;
|
||||
radius = br;
|
||||
}
|
||||
|
||||
partRect = QRectF(poly.at(0), poly.at(1)).adjusted(-1, -1, 1, 1);
|
||||
if (drawRect.intersects(partRect))
|
||||
{
|
||||
partRect = getArrowBoundingRect(poly);
|
||||
if (drawRect.intersects(partRect) && m_showArrow)
|
||||
{
|
||||
drawArrow(poly, &path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path.lineTo(poly.at(0));
|
||||
}
|
||||
}
|
||||
|
||||
painter->drawPath(path);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#ifndef QT_LINE_ITEM_ANGLED_H
|
||||
#define QT_LINE_ITEM_ANGLED_H
|
||||
|
||||
#include "qt/graphics/QtLineItemBase.h"
|
||||
|
||||
class QtLineItemAngled
|
||||
: public QtLineItemBase
|
||||
{
|
||||
public:
|
||||
QtLineItemAngled(QGraphicsItem* parent);
|
||||
virtual ~QtLineItemAngled();
|
||||
|
||||
virtual QPainterPath shape() const;
|
||||
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget);
|
||||
};
|
||||
|
||||
#endif // QT_LINE_ITEM_ANGLED_H
|
||||
+19
-189
@@ -1,30 +1,25 @@
|
||||
#include "qt/graphics/QtAngledLineItem.h"
|
||||
#include "qt/graphics/QtLineItemBase.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <QBrush>
|
||||
#include <QPen>
|
||||
|
||||
#include <QPainter>
|
||||
#include <QStyleOptionGraphicsItem>
|
||||
|
||||
#include "utility/math/Vector2.h"
|
||||
|
||||
QtAngledLineItem::QtAngledLineItem(QGraphicsItem* parent)
|
||||
QtLineItemBase::QtLineItemBase(QGraphicsItem* parent)
|
||||
: QGraphicsLineItem(parent)
|
||||
, m_route(ROUTE_ANY)
|
||||
, m_pivot(PIVOT_THIRD)
|
||||
, m_showArrow(true)
|
||||
, m_onFront(false)
|
||||
, m_onBack(false)
|
||||
, m_horizontalIn(false)
|
||||
, m_showArrow(true)
|
||||
, m_route(ROUTE_ANY)
|
||||
, m_pivot(PIVOT_THIRD)
|
||||
{
|
||||
this->setAcceptHoverEvents(true);
|
||||
this->setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true);
|
||||
}
|
||||
|
||||
QtAngledLineItem::~QtAngledLineItem()
|
||||
QtLineItemBase::~QtLineItemBase()
|
||||
{
|
||||
}
|
||||
|
||||
void QtAngledLineItem::updateLine(
|
||||
void QtLineItemBase::updateLine(
|
||||
Vec4i ownerRect, Vec4i targetRect,
|
||||
Vec4i ownerParentRect, Vec4i targetParentRect,
|
||||
GraphViewStyle::EdgeStyle style,
|
||||
@@ -49,197 +44,32 @@ void QtAngledLineItem::updateLine(
|
||||
this->setPen(QPen(QBrush(style.color.c_str()), style.width + int(log10(weight)), Qt::SolidLine, Qt::RoundCap));
|
||||
}
|
||||
|
||||
void QtAngledLineItem::setRoute(Route route)
|
||||
void QtLineItemBase::setRoute(Route route)
|
||||
{
|
||||
m_route = route;
|
||||
}
|
||||
|
||||
void QtAngledLineItem::setPivot(Pivot pivot)
|
||||
void QtLineItemBase::setPivot(Pivot pivot)
|
||||
{
|
||||
m_pivot = pivot;
|
||||
}
|
||||
|
||||
void QtAngledLineItem::setOnFront(bool front)
|
||||
void QtLineItemBase::setOnFront(bool front)
|
||||
{
|
||||
m_onFront = front;
|
||||
}
|
||||
|
||||
void QtAngledLineItem::setOnBack(bool back)
|
||||
void QtLineItemBase::setOnBack(bool back)
|
||||
{
|
||||
m_onBack = back;
|
||||
}
|
||||
|
||||
void QtAngledLineItem::setHorizontalIn(bool horizontal)
|
||||
void QtLineItemBase::setHorizontalIn(bool horizontal)
|
||||
{
|
||||
m_horizontalIn = horizontal;
|
||||
}
|
||||
|
||||
QPainterPath QtAngledLineItem::shape() const
|
||||
{
|
||||
QPainterPath path;
|
||||
QPolygon poly = getPath();
|
||||
|
||||
for (int i = 0; i < poly.size() - 1; i++)
|
||||
{
|
||||
path.addRect(QRectF(poly.at(i), poly.at(i + 1)).normalized().adjusted(-3, -3, 3, 3));
|
||||
}
|
||||
|
||||
path.addRect(getArrowBoundingRect(poly).adjusted(-3, -3, 3, 3));
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
void QtAngledLineItem::paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget)
|
||||
{
|
||||
painter->setPen(pen());
|
||||
|
||||
QPainterPath path;
|
||||
|
||||
QPolygon poly = getPath();
|
||||
int i = poly.length() - 1;
|
||||
|
||||
path.moveTo(poly.at(i));
|
||||
|
||||
|
||||
// while (i > 0)
|
||||
// {
|
||||
// i--;
|
||||
|
||||
// path.lineTo(poly.at(i));
|
||||
// }
|
||||
// painter->drawPath(path);
|
||||
// return;
|
||||
|
||||
|
||||
QRectF drawRect = options->exposedRect;
|
||||
QRectF partRect;
|
||||
|
||||
int radius = m_style.cornerRadius;
|
||||
int dir = getDirection(poly.at(i), poly.at(i - 1));
|
||||
while (i > 1)
|
||||
{
|
||||
i--;
|
||||
|
||||
QPointF a = poly.at(i);
|
||||
QPointF b = poly.at(i - 1);
|
||||
|
||||
int newDir = getDirection(a, b);
|
||||
int ar = radius;
|
||||
int br = m_style.cornerRadius;
|
||||
|
||||
if (i != 1)
|
||||
{
|
||||
if (dir % 2 == 1 && std::abs(a.y() - b.y()) < 2 * br)
|
||||
{
|
||||
br = std::abs(a.y() - b.y()) / 2;
|
||||
}
|
||||
else if (dir % 2 == 0 && std::abs(a.x() - b.x()) < 2 * br)
|
||||
{
|
||||
br = std::abs(a.x() - b.x()) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case 0: a.setY(a.y() + ar); break;
|
||||
case 1: a.setX(a.x() - ar); break;
|
||||
case 2: a.setY(a.y() - ar); break;
|
||||
case 3: a.setX(a.x() + ar); break;
|
||||
}
|
||||
|
||||
b = poly.at(i);
|
||||
switch (newDir)
|
||||
{
|
||||
case 0: b.setY(b.y() - br); break;
|
||||
case 1: b.setX(b.x() + br); break;
|
||||
case 2: b.setY(b.y() + br); break;
|
||||
case 3: b.setX(b.x() - br); break;
|
||||
}
|
||||
|
||||
partRect = QRectF(poly.at(i + 1), poly.at(i)).adjusted(-1, -1, 1, 1);
|
||||
if (drawRect.intersects(partRect))
|
||||
{
|
||||
path.lineTo(a);
|
||||
}
|
||||
else
|
||||
{
|
||||
path.moveTo(a);
|
||||
}
|
||||
|
||||
partRect = QRectF(a, b).normalized().adjusted(-1, -1, 1, 1);
|
||||
if (drawRect.intersects(partRect))
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
case 0:
|
||||
if (newDir == 1)
|
||||
{
|
||||
path.arcTo(a.x(), b.y(), 2 * br, 2 * ar, 180, -90);
|
||||
}
|
||||
else if (newDir == 3)
|
||||
{
|
||||
path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, 90);
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (newDir == 0)
|
||||
{
|
||||
path.arcTo(a.x() - ar, b.y() - br, 2 * ar, 2 * br, -90, 90);
|
||||
}
|
||||
else if (newDir == 2)
|
||||
{
|
||||
path.arcTo(a.x() - ar, a.y(), 2 * ar, 2 * br, 90, -90);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (newDir == 1)
|
||||
{
|
||||
path.arcTo(a.x(), a.y() - ar, 2 * br, 2 * ar, 180, 90);
|
||||
}
|
||||
else if (newDir == 3)
|
||||
{
|
||||
path.arcTo(b.x() - br, a.y() - ar, 2 * br, 2 * ar, 0, -90);
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (newDir == 0)
|
||||
{
|
||||
path.arcTo(b.x(), b.y() - br, 2 * ar, 2 * br, -90, -90);
|
||||
}
|
||||
else if (newDir == 2)
|
||||
{
|
||||
path.arcTo(b.x(), a.y(), 2 * ar, 2 * br, 90, 90);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
path.moveTo(b);
|
||||
}
|
||||
|
||||
dir = newDir;
|
||||
radius = br;
|
||||
}
|
||||
|
||||
partRect = QRectF(poly.at(0), poly.at(1)).adjusted(-1, -1, 1, 1);
|
||||
if (drawRect.intersects(partRect))
|
||||
{
|
||||
partRect = getArrowBoundingRect(poly);
|
||||
if (drawRect.intersects(partRect) && m_showArrow)
|
||||
{
|
||||
drawArrow(poly, &path);
|
||||
}
|
||||
else
|
||||
{
|
||||
path.lineTo(poly.at(0));
|
||||
}
|
||||
}
|
||||
|
||||
painter->drawPath(path);
|
||||
}
|
||||
|
||||
QPolygon QtAngledLineItem::getPath() const
|
||||
QPolygon QtLineItemBase::getPath() const
|
||||
{
|
||||
if (m_polygon.size() > 0)
|
||||
{
|
||||
@@ -448,7 +278,7 @@ QPolygon QtAngledLineItem::getPath() const
|
||||
return poly;
|
||||
}
|
||||
|
||||
int QtAngledLineItem::getDirection(const QPointF& a, const QPointF& b) const
|
||||
int QtLineItemBase::getDirection(const QPointF& a, const QPointF& b) const
|
||||
{
|
||||
if (a.x() != b.x())
|
||||
{
|
||||
@@ -474,7 +304,7 @@ int QtAngledLineItem::getDirection(const QPointF& a, const QPointF& b) const
|
||||
}
|
||||
}
|
||||
|
||||
QRectF QtAngledLineItem::getArrowBoundingRect(const QPolygon& poly) const
|
||||
QRectF QtLineItemBase::getArrowBoundingRect(const QPolygon& poly) const
|
||||
{
|
||||
int dir = getDirection(poly.at(1), poly.at(0));
|
||||
|
||||
@@ -506,7 +336,7 @@ QRectF QtAngledLineItem::getArrowBoundingRect(const QPolygon& poly) const
|
||||
return rect;
|
||||
}
|
||||
|
||||
void QtAngledLineItem::drawArrow(const QPolygon& poly, QPainterPath* path) const
|
||||
void QtLineItemBase::drawArrow(const QPolygon& poly, QPainterPath* path) const
|
||||
{
|
||||
int dir = getDirection(poly.at(1), poly.at(0));
|
||||
|
||||
@@ -559,7 +389,7 @@ void QtAngledLineItem::drawArrow(const QPolygon& poly, QPainterPath* path) const
|
||||
path->lineTo(tip);
|
||||
}
|
||||
|
||||
void QtAngledLineItem::getPivotPoints(Vec2f* p, const Vec4i& in, const Vec4i& out, int offset, bool target) const
|
||||
void QtLineItemBase::getPivotPoints(Vec2f* p, const Vec4i& in, const Vec4i& out, int offset, bool target) const
|
||||
{
|
||||
float f = m_pivot == PIVOT_THIRD ? (target ? 2 / 3.f : 1 / 3.f) : 1 / 2.f;
|
||||
|
||||
+18
-20
@@ -1,5 +1,5 @@
|
||||
#ifndef QT_ANGLED_LINE_ITEM_H
|
||||
#define QT_ANGLED_LINE_ITEM_H
|
||||
#ifndef QT_LINE_ITEM_BASE_H
|
||||
#define QT_LINE_ITEM_BASE_H
|
||||
|
||||
#include <QGraphicsItem>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
|
||||
class QtAngledLineItem
|
||||
class QtLineItemBase
|
||||
: public QGraphicsLineItem
|
||||
{
|
||||
public:
|
||||
@@ -24,8 +24,8 @@ public:
|
||||
PIVOT_MIDDLE
|
||||
};
|
||||
|
||||
QtAngledLineItem(QGraphicsItem* parent);
|
||||
virtual ~QtAngledLineItem();
|
||||
QtLineItemBase(QGraphicsItem* parent);
|
||||
virtual ~QtLineItemBase();
|
||||
|
||||
void updateLine(
|
||||
Vec4i ownerRect, Vec4i targetRect,
|
||||
@@ -40,10 +40,7 @@ public:
|
||||
void setOnBack(bool back);
|
||||
void setHorizontalIn(bool horizontal);
|
||||
|
||||
virtual QPainterPath shape() const;
|
||||
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget);
|
||||
|
||||
private:
|
||||
protected:
|
||||
QPolygon getPath() const;
|
||||
int getDirection(const QPointF& a, const QPointF& b) const;
|
||||
|
||||
@@ -52,23 +49,24 @@ private:
|
||||
|
||||
void getPivotPoints(Vec2f* p, const Vec4i& in, const Vec4i& out, int offset, bool target) const;
|
||||
|
||||
GraphViewStyle::EdgeStyle m_style;
|
||||
bool m_showArrow;
|
||||
|
||||
bool m_onFront;
|
||||
bool m_onBack;
|
||||
bool m_horizontalIn;
|
||||
|
||||
Route m_route;
|
||||
Pivot m_pivot;
|
||||
|
||||
private:
|
||||
Vec4i m_ownerRect;
|
||||
Vec4i m_targetRect;
|
||||
|
||||
Vec4i m_ownerParentRect;
|
||||
Vec4i m_targetParentRect;
|
||||
|
||||
GraphViewStyle::EdgeStyle m_style;
|
||||
|
||||
Route m_route;
|
||||
Pivot m_pivot;
|
||||
|
||||
bool m_onFront;
|
||||
bool m_onBack;
|
||||
bool m_horizontalIn;
|
||||
bool m_showArrow;
|
||||
|
||||
mutable QPolygon m_polygon;
|
||||
};
|
||||
|
||||
#endif // QT_ANGLED_LINE_ITEM_H
|
||||
#endif // QT_LINE_ITEM_BASE_H
|
||||
@@ -0,0 +1,143 @@
|
||||
#include "qt/graphics/QtLineItemBezier.h"
|
||||
|
||||
#include <QPainter>
|
||||
|
||||
QtLineItemBezier::QtLineItemBezier(QGraphicsItem* parent)
|
||||
: QtLineItemBase(parent)
|
||||
{
|
||||
}
|
||||
|
||||
QtLineItemBezier::~QtLineItemBezier()
|
||||
{
|
||||
}
|
||||
|
||||
QPainterPath QtLineItemBezier::shape() const
|
||||
{
|
||||
QPainterPathStroker stroker;
|
||||
stroker.setWidth(10);
|
||||
stroker.setJoinStyle(Qt::MiterJoin);
|
||||
|
||||
QPainterPath path = stroker.createStroke(getCurve());
|
||||
if (m_showArrow)
|
||||
{
|
||||
path.addRect(getArrowBoundingRect(QtLineItemBase::getPath()).adjusted(-3, -3, 3, 3));
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
void QtLineItemBezier::paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget)
|
||||
{
|
||||
QPainterPath path = getCurve();
|
||||
|
||||
if (m_showArrow)
|
||||
{
|
||||
drawArrow(QtLineItemBase::getPath(), &path);
|
||||
}
|
||||
|
||||
painter->setPen(pen());
|
||||
painter->drawPath(path);
|
||||
}
|
||||
|
||||
QPolygon QtLineItemBezier::getPath() const
|
||||
{
|
||||
QPolygon poly = QtLineItemBase::getPath();
|
||||
QPolygon newPoly;
|
||||
|
||||
QPoint tip = poly.at(0);
|
||||
|
||||
if (m_showArrow && m_style.arrowClosed)
|
||||
{
|
||||
int dir = getDirection(poly.at(1), poly.at(0));
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case 0:
|
||||
tip.ry() += m_style.arrowLength;
|
||||
break;
|
||||
case 1:
|
||||
tip.rx() -= m_style.arrowLength;
|
||||
break;
|
||||
case 2:
|
||||
tip.ry() -= m_style.arrowLength;
|
||||
break;
|
||||
case 3:
|
||||
tip.rx() += m_style.arrowLength;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
newPoly << tip;
|
||||
|
||||
QRect rect(poly.at(0), poly.at(3));
|
||||
|
||||
if (!rect.contains(poly.at(1)))
|
||||
{
|
||||
if (m_route == ROUTE_HORIZONTAL)
|
||||
{
|
||||
int diff;
|
||||
if (std::abs(poly.at(1).x() - poly.at(0).x()) < std::abs(poly.at(2).x() - poly.at(3).x()))
|
||||
{
|
||||
diff = poly.at(1).x() - poly.at(0).x();
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = poly.at(2).x() - poly.at(3).x();
|
||||
}
|
||||
|
||||
newPoly << QPoint(poly.at(1).x() + diff, poly.at(1).y());
|
||||
newPoly << QPoint(poly.at(2).x() + diff, poly.at(2).y());
|
||||
}
|
||||
else
|
||||
{
|
||||
int diff;
|
||||
if (std::abs(poly.at(1).y() - poly.at(0).y()) < std::abs(poly.at(2).y() - poly.at(3).y()))
|
||||
{
|
||||
diff = poly.at(1).y() - poly.at(0).y();
|
||||
}
|
||||
else
|
||||
{
|
||||
diff = poly.at(2).y() - poly.at(3).y();
|
||||
}
|
||||
|
||||
newPoly << QPoint(poly.at(1).x(), poly.at(1).y() + diff);
|
||||
newPoly << QPoint(poly.at(2).x(), poly.at(2).y() + diff);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_route == ROUTE_HORIZONTAL)
|
||||
{
|
||||
newPoly << QPoint((poly.at(3).x() + poly.at(0).x()) / 2, poly.at(0).y());
|
||||
newPoly << QPoint((poly.at(3).x() + poly.at(0).x()) / 2, poly.at(3).y());
|
||||
}
|
||||
else
|
||||
{
|
||||
newPoly << QPoint(poly.at(0).x(), (poly.at(3).y() + poly.at(0).y()) / 2);
|
||||
newPoly << QPoint(poly.at(3).x(), (poly.at(3).y() + poly.at(0).y()) / 2);
|
||||
}
|
||||
}
|
||||
|
||||
newPoly << poly.at(3);
|
||||
return newPoly;
|
||||
}
|
||||
|
||||
QPainterPath QtLineItemBezier::getCurve() const
|
||||
{
|
||||
QPolygon poly = getPath();
|
||||
|
||||
QPainterPath path;
|
||||
path.moveTo(poly.at(3));
|
||||
path.cubicTo(
|
||||
poly.at(2),
|
||||
poly.at(1),
|
||||
poly.at(0)
|
||||
);
|
||||
|
||||
// QPainterPath path;
|
||||
// path.moveTo(poly.at(3));
|
||||
// path.lineTo(poly.at(2));
|
||||
// path.lineTo(poly.at(1));
|
||||
// path.lineTo(poly.at(0));
|
||||
|
||||
return path;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
#ifndef QT_LINE_ITEM_BEZIER_H
|
||||
#define QT_LINE_ITEM_BEZIER_H
|
||||
|
||||
#include "qt/graphics/QtLineItemBase.h"
|
||||
|
||||
class QtLineItemBezier
|
||||
: public QtLineItemBase
|
||||
{
|
||||
public:
|
||||
QtLineItemBezier(QGraphicsItem* parent);
|
||||
virtual ~QtLineItemBezier();
|
||||
|
||||
virtual QPainterPath shape() const;
|
||||
virtual void paint(QPainter* painter, const QStyleOptionGraphicsItem* options, QWidget* widget);
|
||||
|
||||
protected:
|
||||
QPolygon getPath() const;
|
||||
|
||||
private:
|
||||
QPainterPath getCurve() const;
|
||||
};
|
||||
|
||||
#endif // QT_LINE_ITEM_BEZIER_H
|
||||
@@ -0,0 +1,38 @@
|
||||
#include "qt/graphics/QtLineItemStraight.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QPen>
|
||||
|
||||
QtLineItemStraight::QtLineItemStraight(QGraphicsItem* parent)
|
||||
: QGraphicsLineItem(parent)
|
||||
{
|
||||
this->setAcceptHoverEvents(true);
|
||||
}
|
||||
|
||||
QtLineItemStraight::~QtLineItemStraight()
|
||||
{
|
||||
}
|
||||
|
||||
void QtLineItemStraight::updateLine(Vec2i origin, Vec2i target, GraphViewStyle::EdgeStyle style)
|
||||
{
|
||||
prepareGeometryChange();
|
||||
|
||||
setLine(origin.x(), origin.y(), target.x(), target.y());
|
||||
|
||||
setPen(QPen(QBrush(style.color.c_str()), style.width, Qt::SolidLine));
|
||||
}
|
||||
|
||||
QPainterPath QtLineItemStraight::shape() const
|
||||
{
|
||||
QPainterPath path;
|
||||
QLineF l = line();
|
||||
|
||||
path.moveTo(l.p1());
|
||||
path.lineTo(l.p2());
|
||||
|
||||
QPainterPathStroker stroker;
|
||||
stroker.setWidth(10);
|
||||
stroker.setJoinStyle(Qt::MiterJoin);
|
||||
|
||||
return stroker.createStroke(path);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#ifndef QT_LINE_ITEM_STRAIGHT_H
|
||||
#define QT_LINE_ITEM_STRAIGHT_H
|
||||
|
||||
#include <QGraphicsItem>
|
||||
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
|
||||
class QtLineItemStraight
|
||||
: public QGraphicsLineItem
|
||||
{
|
||||
public:
|
||||
QtLineItemStraight(QGraphicsItem* parent);
|
||||
virtual ~QtLineItemStraight();
|
||||
|
||||
void updateLine(Vec2i origin, Vec2i target, GraphViewStyle::EdgeStyle style);
|
||||
|
||||
virtual QPainterPath shape() const;
|
||||
};
|
||||
|
||||
#endif // QT_LINE_ITEM_STRAIGHT_H
|
||||
@@ -1,110 +0,0 @@
|
||||
#include "qt/graphics/QtStraightLineItem.h"
|
||||
|
||||
#include <QBrush>
|
||||
#include <QPen>
|
||||
|
||||
#include "utility/math/Vector2.h"
|
||||
#include "utility/utility.h"
|
||||
|
||||
#include "qt/graphics/QtCountCircleItem.h"
|
||||
|
||||
QtStraightLineItem::QtStraightLineItem(QGraphicsItem* parent)
|
||||
: QGraphicsLineItem(parent)
|
||||
{
|
||||
this->setAcceptHoverEvents(true);
|
||||
|
||||
m_circle = new QtCountCircleItem(this);
|
||||
|
||||
m_arrowLeft = new QGraphicsLineItem(this);
|
||||
m_arrowRight = new QGraphicsLineItem(this);
|
||||
}
|
||||
|
||||
QtStraightLineItem::~QtStraightLineItem()
|
||||
{
|
||||
}
|
||||
|
||||
void QtStraightLineItem::updateLine(
|
||||
Vec4i ownerRect, Vec4i targetRect, int number,
|
||||
GraphViewStyle::EdgeStyle style, GraphViewStyle::NodeStyle countStyle, bool showArrow
|
||||
){
|
||||
prepareGeometryChange();
|
||||
|
||||
const Vec4i& o = ownerRect;
|
||||
const Vec4i& t = targetRect;
|
||||
|
||||
Vec2f oc((o.x + o.z) / 2, (o.y + o.w) / 2);
|
||||
Vec2f tc((t.x + t.z) / 2, (t.y + t.w) / 2);
|
||||
|
||||
Vec2f op;
|
||||
Vec2f tp;
|
||||
|
||||
bool intersects = false;
|
||||
for (int i = 0; !intersects && i < 4; i++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.y), Vec2f(o.x, o.w), &op); break;
|
||||
case 1: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.y), Vec2f(o.z, o.y), &op); break;
|
||||
case 2: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.z, o.y), Vec2f(o.z, o.w), &op); break;
|
||||
case 3: intersects = utility::intersectionPoint(oc, tc, Vec2f(o.x, o.w), Vec2f(o.z, o.w), &op); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!intersects)
|
||||
{
|
||||
op = oc;
|
||||
}
|
||||
|
||||
intersects = false;
|
||||
for (int i = 0; !intersects && i < 4; i++)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.y), Vec2f(t.x, t.w), &tp); break;
|
||||
case 1: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.y), Vec2f(t.z, t.y), &tp); break;
|
||||
case 2: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.z, t.y), Vec2f(t.z, t.w), &tp); break;
|
||||
case 3: intersects = utility::intersectionPoint(oc, tc, Vec2f(t.x, t.w), Vec2f(t.z, t.w), &tp); break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!intersects)
|
||||
{
|
||||
tp = tc;
|
||||
}
|
||||
|
||||
this->setLine(oc.x, oc.y, tc.x, tc.y);
|
||||
|
||||
Vec2f mid = (op + tp) / 2;
|
||||
m_circle->setPosition(mid);
|
||||
m_circle->setNumber(number);
|
||||
|
||||
size_t radius = m_circle->getRadius();
|
||||
|
||||
if (showArrow)
|
||||
{
|
||||
Vec2f unit = (tp - op).normalize();
|
||||
Vec2f nUnit(-unit.y, unit.x);
|
||||
Vec2f arrow = mid + unit * (radius + 13);
|
||||
|
||||
Vec2f arrowSide = mid + unit * (radius + 6) + nUnit * 7;
|
||||
m_arrowRight->setLine(arrow.x, arrow.y, arrowSide.x, arrowSide.y);
|
||||
|
||||
arrowSide -= nUnit * 14;
|
||||
m_arrowLeft->setLine(arrow.x, arrow.y, arrowSide.x, arrowSide.y);
|
||||
|
||||
m_arrowLeft->show();
|
||||
m_arrowRight->show();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_arrowLeft->hide();
|
||||
m_arrowRight->hide();
|
||||
}
|
||||
|
||||
this->setPen(QPen(QBrush(style.color.c_str()), style.width, Qt::SolidLine, Qt::RoundCap));
|
||||
|
||||
m_circle->setStyle(countStyle.color.fill.c_str(), countStyle.color.text.c_str(), countStyle.color.border.c_str(), 1);
|
||||
|
||||
m_arrowLeft->setPen(QPen(QBrush(countStyle.color.border.c_str()), 1, Qt::SolidLine, Qt::RoundCap));
|
||||
m_arrowRight->setPen(QPen(QBrush(countStyle.color.border.c_str()), 1, Qt::SolidLine, Qt::RoundCap));
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#ifndef QT_STRAIGHT_LINE_ITEM_H
|
||||
#define QT_STRAIGHT_LINE_ITEM_H
|
||||
|
||||
#include <QGraphicsItem>
|
||||
|
||||
#include "utility/math/Vector4.h"
|
||||
|
||||
#include "component/view/GraphViewStyle.h"
|
||||
|
||||
class QtCountCircleItem;
|
||||
|
||||
class QtStraightLineItem
|
||||
: public QGraphicsLineItem
|
||||
{
|
||||
public:
|
||||
QtStraightLineItem(QGraphicsItem* parent);
|
||||
virtual ~QtStraightLineItem();
|
||||
|
||||
void updateLine(
|
||||
Vec4i ownerRect, Vec4i targetRect, int number,
|
||||
GraphViewStyle::EdgeStyle style, GraphViewStyle::NodeStyle countStyle, bool showArrow);
|
||||
|
||||
private:
|
||||
QtCountCircleItem* m_circle;
|
||||
|
||||
QGraphicsLineItem* m_arrowLeft;
|
||||
QGraphicsLineItem* m_arrowRight;
|
||||
};
|
||||
|
||||
#endif // QT_STRAIGHT_LINE_ITEM_H
|
||||
Reference in New Issue
Block a user