GUI: formatting
This commit is contained in:
parent
4c10421171
commit
9b2ebb68ee
|
|
@ -1,256 +1,256 @@
|
|||
#include "GraphEdge.h"
|
||||
|
||||
|
||||
GraphEdge::GraphEdge(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect, EDGE_TYPE edgeType) : QAbstractGraphicsShapeItem()
|
||||
{
|
||||
_edgeType = edgeType;
|
||||
|
||||
if(_edgeType == EDGE_LEFT)
|
||||
_edgeColor = Qt::red;
|
||||
else
|
||||
_edgeColor = Qt::green;
|
||||
|
||||
QList<QPointF> linePoints = calculateLine(start, end, bends, sourceRect, targetRect);
|
||||
// for(auto p : linePoints)
|
||||
// qDebug() << p;
|
||||
QList<QPointF> arrowPoints = calculateArrow(linePoints);
|
||||
_boundingRect = calculateBoundingRect(linePoints, arrowPoints);
|
||||
preparePainterPaths(linePoints, arrowPoints);
|
||||
}
|
||||
|
||||
QRectF GraphEdge::boundingRect() const
|
||||
{
|
||||
return _boundingRect;
|
||||
}
|
||||
|
||||
void GraphEdge::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(widget);
|
||||
|
||||
//save painter
|
||||
painter->save();
|
||||
|
||||
#ifdef _DEBUG
|
||||
//draw bounding rect
|
||||
painter->setPen(QPen(Qt::red, 1));
|
||||
painter->drawRect(boundingRect());
|
||||
#endif //_DEBUG
|
||||
|
||||
//set painter options
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int lineSize = 2;
|
||||
|
||||
//draw line
|
||||
painter->setPen(QPen(_edgeColor, lineSize));
|
||||
painter->drawPath(_line);
|
||||
|
||||
//draw arrow
|
||||
painter->setPen(QPen(_edgeColor, lineSize));
|
||||
painter->drawPath(_arrow);
|
||||
|
||||
//restore painter
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
qreal GraphEdge::calculateDistance(QPointF p1, QPointF p2)
|
||||
{
|
||||
QPointF d = p2 - p1;
|
||||
return sqrt(d.x() * d.x() + d.y() * d.y());
|
||||
}
|
||||
|
||||
QPointF GraphEdge::calculateNearestIntersect(QRectF rect, QPointF p1, QPointF p2)
|
||||
{
|
||||
/*qDebug() << "calculateNearest";
|
||||
qDebug() << "rect" << rect.topLeft() << rect.bottomRight();
|
||||
qDebug() << "p1" << p1;
|
||||
qDebug() << "p2" << p2;*/
|
||||
|
||||
//y=a*x+b
|
||||
//a = dy/dx = (p1.y-p2.y)/(p1.x-p2.x)
|
||||
//b = p1.y - p1.x;
|
||||
|
||||
qreal div = p1.x()-p2.x();
|
||||
|
||||
if(div == 0)
|
||||
{
|
||||
QPointF i1(p1.x(), rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
QPointF i2(p1.x(), rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
|
||||
if(p2.y() < p1.y())
|
||||
return i1;
|
||||
else
|
||||
return i2;
|
||||
}
|
||||
else
|
||||
{
|
||||
QPointF result;
|
||||
qreal bestDist = 10e99;
|
||||
|
||||
qreal a = (p1.y()-p2.y()) / div;
|
||||
qreal b = p1.y() - a * p1.x();
|
||||
//qDebug() << "a" << a << "b" << b;
|
||||
|
||||
//intersect 1
|
||||
//rect.top() = a*x+b;
|
||||
//x = (b - rect.top()) / -a
|
||||
QPointF i1((b - rect.top()) / -a, rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
//qDebug() << "consider?" << rect.contains(i1);
|
||||
if(rect.contains(i1))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i1);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i1;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 2
|
||||
//rect.bottom() = a*x+b
|
||||
//x = (b - rect.bottom()) / -a
|
||||
QPointF i2((b - rect.bottom()) / -a, rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
//qDebug() << "consider?" << rect.contains(i2);
|
||||
if(rect.contains(i2))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i2);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i2;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 3
|
||||
//x=rect.left()
|
||||
QPointF i3(rect.left(), a * rect.left() + b);
|
||||
//qDebug() << "i3" << i3;
|
||||
//qDebug() << "consider?" << rect.contains(i3);
|
||||
if(rect.contains(i3))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i3);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i3;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 4
|
||||
//x=rect.right()
|
||||
QPointF i4(rect.right(), a * rect.right() + b);
|
||||
//qDebug() << "i4" << i4;
|
||||
//qDebug() << "consider?" << rect.contains(i4);
|
||||
if(rect.contains(i4))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i4);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i4;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//qDebug() << " ";
|
||||
}
|
||||
|
||||
QList<QPointF> GraphEdge::calculateLine(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect)
|
||||
{
|
||||
QList<QPointF> linePoints;
|
||||
linePoints << start;
|
||||
for(auto p : bends)
|
||||
linePoints << QPointF(p.m_x, p.m_y);
|
||||
linePoints << end;
|
||||
|
||||
QPointF nearestI = calculateNearestIntersect(sourceRect, linePoints[0], linePoints[1]);
|
||||
linePoints[0]=nearestI;
|
||||
int len = linePoints.length();
|
||||
nearestI = calculateNearestIntersect(targetRect, linePoints[len-1], linePoints[len-2]);
|
||||
linePoints[len-1]=nearestI;
|
||||
|
||||
return linePoints;
|
||||
}
|
||||
|
||||
QList<QPointF> GraphEdge::calculateArrow(const QList<QPointF> & linePoints)
|
||||
{
|
||||
//arrow
|
||||
int len=linePoints.length();
|
||||
QLineF perpLine = QLineF(linePoints[len-1], linePoints[len-2]).normalVector();
|
||||
|
||||
qreal arrowLen = 6;
|
||||
|
||||
QLineF a;
|
||||
a.setP1(linePoints[len-1]);
|
||||
a.setAngle(perpLine.angle() - 45);
|
||||
a.setLength(arrowLen);
|
||||
|
||||
QLineF b;
|
||||
b.setP1(linePoints[len-1]);
|
||||
b.setAngle(perpLine.angle() - 135);
|
||||
b.setLength(arrowLen);
|
||||
|
||||
QLineF c;
|
||||
c.setP1(a.p2());
|
||||
c.setP2(b.p2());
|
||||
|
||||
QList<QPointF> arrowPoints;
|
||||
arrowPoints << a.p1() << a.p2() << b.p1() << b.p2() << c.p1() << c.p2();
|
||||
return arrowPoints;
|
||||
}
|
||||
|
||||
QRectF GraphEdge::calculateBoundingRect(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
QList<QPointF> allPoints;
|
||||
allPoints << linePoints << arrowPoints;
|
||||
//find top-left and bottom-right points for the bounding rect
|
||||
QPointF topLeft = allPoints[0];
|
||||
QPointF bottomRight = topLeft;
|
||||
for(auto p : allPoints)
|
||||
{
|
||||
qreal x = p.x();
|
||||
qreal y = p.y();
|
||||
|
||||
if(x < topLeft.x())
|
||||
topLeft.setX(x);
|
||||
if(y < topLeft.y())
|
||||
topLeft.setY(y);
|
||||
|
||||
if(x > bottomRight.x())
|
||||
bottomRight.setX(x);
|
||||
if(y > bottomRight.y())
|
||||
bottomRight.setY(y);
|
||||
}
|
||||
return QRectF(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
void GraphEdge::preparePainterPaths(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
//edge line
|
||||
QPolygonF polyLine;
|
||||
for(auto p : linePoints)
|
||||
polyLine << p;
|
||||
_line.addPolygon(polyLine);
|
||||
|
||||
//arrow
|
||||
QPolygonF polyArrow;
|
||||
for(auto p : arrowPoints)
|
||||
polyArrow << p;
|
||||
_arrow.addPolygon(polyArrow);
|
||||
}
|
||||
|
||||
void GraphEdge::setEdgeColor(QBrush edgeColor)
|
||||
{
|
||||
_edgeColor = edgeColor;
|
||||
}
|
||||
|
||||
GraphEdge::EDGE_TYPE GraphEdge::getEdgeType()
|
||||
{
|
||||
return _edgeType;
|
||||
}
|
||||
|
||||
#include "GraphEdge.h"
|
||||
|
||||
|
||||
GraphEdge::GraphEdge(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect, EDGE_TYPE edgeType) : QAbstractGraphicsShapeItem()
|
||||
{
|
||||
_edgeType = edgeType;
|
||||
|
||||
if(_edgeType == EDGE_LEFT)
|
||||
_edgeColor = Qt::red;
|
||||
else
|
||||
_edgeColor = Qt::green;
|
||||
|
||||
QList<QPointF> linePoints = calculateLine(start, end, bends, sourceRect, targetRect);
|
||||
// for(auto p : linePoints)
|
||||
// qDebug() << p;
|
||||
QList<QPointF> arrowPoints = calculateArrow(linePoints);
|
||||
_boundingRect = calculateBoundingRect(linePoints, arrowPoints);
|
||||
preparePainterPaths(linePoints, arrowPoints);
|
||||
}
|
||||
|
||||
QRectF GraphEdge::boundingRect() const
|
||||
{
|
||||
return _boundingRect;
|
||||
}
|
||||
|
||||
void GraphEdge::paint(QPainter* painter, const QStyleOptionGraphicsItem* option, QWidget* widget)
|
||||
{
|
||||
Q_UNUSED(option);
|
||||
Q_UNUSED(widget);
|
||||
|
||||
//save painter
|
||||
painter->save();
|
||||
|
||||
#ifdef _DEBUG
|
||||
//draw bounding rect
|
||||
painter->setPen(QPen(Qt::red, 1));
|
||||
painter->drawRect(boundingRect());
|
||||
#endif //_DEBUG
|
||||
|
||||
//set painter options
|
||||
painter->setRenderHint(QPainter::Antialiasing);
|
||||
|
||||
int lineSize = 2;
|
||||
|
||||
//draw line
|
||||
painter->setPen(QPen(_edgeColor, lineSize));
|
||||
painter->drawPath(_line);
|
||||
|
||||
//draw arrow
|
||||
painter->setPen(QPen(_edgeColor, lineSize));
|
||||
painter->drawPath(_arrow);
|
||||
|
||||
//restore painter
|
||||
painter->restore();
|
||||
}
|
||||
|
||||
qreal GraphEdge::calculateDistance(QPointF p1, QPointF p2)
|
||||
{
|
||||
QPointF d = p2 - p1;
|
||||
return sqrt(d.x() * d.x() + d.y() * d.y());
|
||||
}
|
||||
|
||||
QPointF GraphEdge::calculateNearestIntersect(QRectF rect, QPointF p1, QPointF p2)
|
||||
{
|
||||
/*qDebug() << "calculateNearest";
|
||||
qDebug() << "rect" << rect.topLeft() << rect.bottomRight();
|
||||
qDebug() << "p1" << p1;
|
||||
qDebug() << "p2" << p2;*/
|
||||
|
||||
//y=a*x+b
|
||||
//a = dy/dx = (p1.y-p2.y)/(p1.x-p2.x)
|
||||
//b = p1.y - p1.x;
|
||||
|
||||
qreal div = p1.x()-p2.x();
|
||||
|
||||
if(div == 0)
|
||||
{
|
||||
QPointF i1(p1.x(), rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
QPointF i2(p1.x(), rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
|
||||
if(p2.y() < p1.y())
|
||||
return i1;
|
||||
else
|
||||
return i2;
|
||||
}
|
||||
else
|
||||
{
|
||||
QPointF result;
|
||||
qreal bestDist = 10e99;
|
||||
|
||||
qreal a = (p1.y()-p2.y()) / div;
|
||||
qreal b = p1.y() - a * p1.x();
|
||||
//qDebug() << "a" << a << "b" << b;
|
||||
|
||||
//intersect 1
|
||||
//rect.top() = a*x+b;
|
||||
//x = (b - rect.top()) / -a
|
||||
QPointF i1((b - rect.top()) / -a, rect.top());
|
||||
//qDebug() << "i1" << i1;
|
||||
//qDebug() << "consider?" << rect.contains(i1);
|
||||
if(rect.contains(i1))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i1);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i1;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 2
|
||||
//rect.bottom() = a*x+b
|
||||
//x = (b - rect.bottom()) / -a
|
||||
QPointF i2((b - rect.bottom()) / -a, rect.bottom());
|
||||
//qDebug() << "i2" << i2;
|
||||
//qDebug() << "consider?" << rect.contains(i2);
|
||||
if(rect.contains(i2))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i2);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i2;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 3
|
||||
//x=rect.left()
|
||||
QPointF i3(rect.left(), a * rect.left() + b);
|
||||
//qDebug() << "i3" << i3;
|
||||
//qDebug() << "consider?" << rect.contains(i3);
|
||||
if(rect.contains(i3))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i3);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i3;
|
||||
}
|
||||
}
|
||||
|
||||
//intersect 4
|
||||
//x=rect.right()
|
||||
QPointF i4(rect.right(), a * rect.right() + b);
|
||||
//qDebug() << "i4" << i4;
|
||||
//qDebug() << "consider?" << rect.contains(i4);
|
||||
if(rect.contains(i4))
|
||||
{
|
||||
qreal dist = calculateDistance(p2, i4);
|
||||
if(dist < bestDist)
|
||||
{
|
||||
bestDist = dist;
|
||||
result = i4;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
//qDebug() << " ";
|
||||
}
|
||||
|
||||
QList<QPointF> GraphEdge::calculateLine(QPointF start, QPointF end, ogdf::DPolyline bends, QRectF sourceRect, QRectF targetRect)
|
||||
{
|
||||
QList<QPointF> linePoints;
|
||||
linePoints << start;
|
||||
for(auto p : bends)
|
||||
linePoints << QPointF(p.m_x, p.m_y);
|
||||
linePoints << end;
|
||||
|
||||
QPointF nearestI = calculateNearestIntersect(sourceRect, linePoints[0], linePoints[1]);
|
||||
linePoints[0]=nearestI;
|
||||
int len = linePoints.length();
|
||||
nearestI = calculateNearestIntersect(targetRect, linePoints[len-1], linePoints[len-2]);
|
||||
linePoints[len-1]=nearestI;
|
||||
|
||||
return linePoints;
|
||||
}
|
||||
|
||||
QList<QPointF> GraphEdge::calculateArrow(const QList<QPointF> & linePoints)
|
||||
{
|
||||
//arrow
|
||||
int len=linePoints.length();
|
||||
QLineF perpLine = QLineF(linePoints[len-1], linePoints[len-2]).normalVector();
|
||||
|
||||
qreal arrowLen = 6;
|
||||
|
||||
QLineF a;
|
||||
a.setP1(linePoints[len-1]);
|
||||
a.setAngle(perpLine.angle() - 45);
|
||||
a.setLength(arrowLen);
|
||||
|
||||
QLineF b;
|
||||
b.setP1(linePoints[len-1]);
|
||||
b.setAngle(perpLine.angle() - 135);
|
||||
b.setLength(arrowLen);
|
||||
|
||||
QLineF c;
|
||||
c.setP1(a.p2());
|
||||
c.setP2(b.p2());
|
||||
|
||||
QList<QPointF> arrowPoints;
|
||||
arrowPoints << a.p1() << a.p2() << b.p1() << b.p2() << c.p1() << c.p2();
|
||||
return arrowPoints;
|
||||
}
|
||||
|
||||
QRectF GraphEdge::calculateBoundingRect(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
QList<QPointF> allPoints;
|
||||
allPoints << linePoints << arrowPoints;
|
||||
//find top-left and bottom-right points for the bounding rect
|
||||
QPointF topLeft = allPoints[0];
|
||||
QPointF bottomRight = topLeft;
|
||||
for(auto p : allPoints)
|
||||
{
|
||||
qreal x = p.x();
|
||||
qreal y = p.y();
|
||||
|
||||
if(x < topLeft.x())
|
||||
topLeft.setX(x);
|
||||
if(y < topLeft.y())
|
||||
topLeft.setY(y);
|
||||
|
||||
if(x > bottomRight.x())
|
||||
bottomRight.setX(x);
|
||||
if(y > bottomRight.y())
|
||||
bottomRight.setY(y);
|
||||
}
|
||||
return QRectF(topLeft, bottomRight);
|
||||
}
|
||||
|
||||
void GraphEdge::preparePainterPaths(const QList<QPointF> & linePoints, const QList<QPointF> & arrowPoints)
|
||||
{
|
||||
//edge line
|
||||
QPolygonF polyLine;
|
||||
for(auto p : linePoints)
|
||||
polyLine << p;
|
||||
_line.addPolygon(polyLine);
|
||||
|
||||
//arrow
|
||||
QPolygonF polyArrow;
|
||||
for(auto p : arrowPoints)
|
||||
polyArrow << p;
|
||||
_arrow.addPolygon(polyArrow);
|
||||
}
|
||||
|
||||
void GraphEdge::setEdgeColor(QBrush edgeColor)
|
||||
{
|
||||
_edgeColor = edgeColor;
|
||||
}
|
||||
|
||||
GraphEdge::EDGE_TYPE GraphEdge::getEdgeType()
|
||||
{
|
||||
return _edgeType;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,208 +1,208 @@
|
|||
#include "GraphNode.h"
|
||||
|
||||
#include <QStyleOption>
|
||||
|
||||
GraphNode::GraphNode() : QFrame()
|
||||
{
|
||||
}
|
||||
|
||||
GraphNode::GraphNode(std::vector<Instruction_t> &instructionsVector, duint address)
|
||||
{
|
||||
mAddress = address;
|
||||
mInstructionsVector = instructionsVector;
|
||||
mHighlightInstructionAt = -1;
|
||||
|
||||
updateTokensVector();
|
||||
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setContentsMargins(0,0,0,0);
|
||||
setMouseTracking(true); // required for mouse move event
|
||||
installEventFilter(this);
|
||||
}
|
||||
|
||||
GraphNode::GraphNode(const GraphNode & other)
|
||||
{
|
||||
setInstructionsVector(other.mInstructionsVector);
|
||||
}
|
||||
|
||||
GraphNode & GraphNode::operator=(const GraphNode & other)
|
||||
{
|
||||
// TODO : Complete this
|
||||
setInstructionsVector(other.mInstructionsVector);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QRectF GraphNode::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, mCachedWidth, mCachedHeight);
|
||||
}
|
||||
|
||||
void GraphNode::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
painter.fillRect(0, 0, mCachedWidth, mCachedHeight, Qt::white);
|
||||
|
||||
// Draw node borders
|
||||
painter.setPen(QPen(Qt::black, 1));
|
||||
painter.drawLine(0, mLineHeight, 0, mCachedHeight-1);
|
||||
painter.drawLine(mCachedWidth-1, mLineHeight, mCachedWidth-1, mCachedHeight-1);
|
||||
painter.drawLine(0, mCachedHeight-1, mCachedWidth-1, mCachedHeight-1);
|
||||
|
||||
// QStyleOption opt;
|
||||
// opt.init(this);
|
||||
// style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||||
|
||||
//draw node contents
|
||||
painter.setFont(this->mFont);
|
||||
int i = 0;
|
||||
|
||||
int x = mSpacingX/2, y = mLineHeight + mSpacingY/2;
|
||||
|
||||
// Block address
|
||||
painter.fillRect(0, 0, mCachedWidth, mLineHeight, Qt::cyan);
|
||||
painter.setPen(Qt::black);
|
||||
painter.drawText(0, 0, mCachedWidth, mLineHeight, Qt::AlignHCenter | Qt::AlignVCenter, "0x" + QString::number(mAddress, 16).toUpper());
|
||||
|
||||
// Block instructions
|
||||
for(QList<RichTextPainter::CustomRichText_t> &richText : mRichTextVector)
|
||||
{
|
||||
RichTextPainter::paintRichText(&painter, x, y, mCachedWidth, mLineHeight, 0, &richText, QFontMetrics(this->mFont).width(QChar(' ')));
|
||||
|
||||
if(mHighlightInstructionAt == i)
|
||||
painter.fillRect(0, y, mCachedWidth, mLineHeight, QBrush(QColor(0, 0, 0, 150)));
|
||||
|
||||
y += mLineHeight + mLineSpacingY;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dsint GraphNode::getInstructionIndexAtPos(const QPoint &pos) const
|
||||
{
|
||||
// Gets the instruction index at the cursor position
|
||||
duint instructionIndex = -1;
|
||||
for(duint i = 0; i < mInstructionsVector.size(); i++)
|
||||
{
|
||||
dsint currentInstructionMinHeight = (i+1) * (mLineHeight + mLineSpacingY) + (mSpacingY/2);
|
||||
dsint currentInstructionMaxHeight = (i+2) * (mLineHeight+mLineSpacingY) + (mSpacingY/2);
|
||||
|
||||
if(pos.y() >= currentInstructionMinHeight && pos.y() <= currentInstructionMaxHeight)
|
||||
{
|
||||
instructionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return instructionIndex;
|
||||
}
|
||||
|
||||
bool GraphNode::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
// Mouse click
|
||||
if(event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if(mouseEvent->button() != Qt::LeftButton)
|
||||
return true;
|
||||
|
||||
duint clickedInstructionIndex = getInstructionIndexAtPos(mouseEvent->pos());
|
||||
|
||||
// No instruction clicked
|
||||
if(clickedInstructionIndex == -1)
|
||||
return true;
|
||||
|
||||
Instruction_t clickedInstruction = mInstructionsVector.at(clickedInstructionIndex);
|
||||
if(clickedInstruction.branchDestination != 0)
|
||||
emit drawGraphAt(clickedInstruction.branchDestination);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mouse move
|
||||
else if(event->type() == QEvent::MouseMove)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
mHighlightInstructionAt = getInstructionIndexAtPos(mouseEvent->pos());
|
||||
repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Leaving widget area
|
||||
else if(event->type() == QEvent::Leave)
|
||||
{
|
||||
mHighlightInstructionAt = -1;
|
||||
repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GraphNode::updateTokensVector()
|
||||
{
|
||||
for(duint i=0; i < mInstructionsVector.size(); i++)
|
||||
{
|
||||
mTokensVector.push_back(mInstructionsVector[i].tokens);
|
||||
}
|
||||
|
||||
updateCache();
|
||||
updateRichText();
|
||||
}
|
||||
|
||||
void GraphNode::setInstructionsVector(const std::vector<Instruction_t> &instructionsVector)
|
||||
{
|
||||
mInstructionsVector = instructionsVector;
|
||||
}
|
||||
|
||||
void GraphNode::updateCache()
|
||||
{
|
||||
QString maxInstruction = getLongestInstruction();
|
||||
|
||||
QFontMetrics metrics(this->mFont);
|
||||
mCachedWidth = metrics.width(maxInstruction) + mSpacingX;
|
||||
mCachedHeight =((metrics.height() + mLineSpacingY) * mInstructionsVector.size()) + metrics.height() + mSpacingY; // +metrics.height() => for block address line
|
||||
mLineHeight = metrics.height();
|
||||
}
|
||||
|
||||
void GraphNode::updateRichText()
|
||||
{
|
||||
for(CapstoneTokenizer::InstructionToken &token : mTokensVector)
|
||||
{
|
||||
QList<RichTextPainter::CustomRichText_t> richText;
|
||||
CapstoneTokenizer::TokenToRichText(token, richText, 0);
|
||||
mRichTextVector.push_back(richText);
|
||||
}
|
||||
}
|
||||
|
||||
QString GraphNode::getLongestInstruction()
|
||||
{
|
||||
dsint maxInstructionLength = 0;
|
||||
QString maxInstruction = "";
|
||||
|
||||
for(CapstoneTokenizer::InstructionToken &token : mTokensVector)
|
||||
{
|
||||
dsint currentInstructionLength = 0;
|
||||
QString currentInstruction = "";
|
||||
for(CapstoneTokenizer::SingleToken &singleToken : token.tokens)
|
||||
{
|
||||
currentInstructionLength += singleToken.text.length();
|
||||
currentInstruction += singleToken.text;
|
||||
}
|
||||
|
||||
if(currentInstructionLength > maxInstructionLength)
|
||||
{
|
||||
maxInstructionLength = currentInstructionLength;
|
||||
maxInstruction = currentInstruction;
|
||||
}
|
||||
}
|
||||
|
||||
return maxInstruction;
|
||||
}
|
||||
|
||||
duint GraphNode::address()
|
||||
{
|
||||
return mAddress;
|
||||
}
|
||||
#include "GraphNode.h"
|
||||
|
||||
#include <QStyleOption>
|
||||
|
||||
GraphNode::GraphNode() : QFrame()
|
||||
{
|
||||
}
|
||||
|
||||
GraphNode::GraphNode(std::vector<Instruction_t> &instructionsVector, duint address)
|
||||
{
|
||||
mAddress = address;
|
||||
mInstructionsVector = instructionsVector;
|
||||
mHighlightInstructionAt = -1;
|
||||
|
||||
updateTokensVector();
|
||||
|
||||
setAttribute(Qt::WA_TranslucentBackground);
|
||||
setContentsMargins(0,0,0,0);
|
||||
setMouseTracking(true); // required for mouse move event
|
||||
installEventFilter(this);
|
||||
}
|
||||
|
||||
GraphNode::GraphNode(const GraphNode & other)
|
||||
{
|
||||
setInstructionsVector(other.mInstructionsVector);
|
||||
}
|
||||
|
||||
GraphNode & GraphNode::operator=(const GraphNode & other)
|
||||
{
|
||||
// TODO : Complete this
|
||||
setInstructionsVector(other.mInstructionsVector);
|
||||
return *this;
|
||||
}
|
||||
|
||||
QRectF GraphNode::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, mCachedWidth, mCachedHeight);
|
||||
}
|
||||
|
||||
void GraphNode::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
||||
QPainter painter(this);
|
||||
|
||||
painter.fillRect(0, 0, mCachedWidth, mCachedHeight, Qt::white);
|
||||
|
||||
// Draw node borders
|
||||
painter.setPen(QPen(Qt::black, 1));
|
||||
painter.drawLine(0, mLineHeight, 0, mCachedHeight-1);
|
||||
painter.drawLine(mCachedWidth-1, mLineHeight, mCachedWidth-1, mCachedHeight-1);
|
||||
painter.drawLine(0, mCachedHeight-1, mCachedWidth-1, mCachedHeight-1);
|
||||
|
||||
// QStyleOption opt;
|
||||
// opt.init(this);
|
||||
// style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this);
|
||||
|
||||
//draw node contents
|
||||
painter.setFont(this->mFont);
|
||||
int i = 0;
|
||||
|
||||
int x = mSpacingX/2, y = mLineHeight + mSpacingY/2;
|
||||
|
||||
// Block address
|
||||
painter.fillRect(0, 0, mCachedWidth, mLineHeight, Qt::cyan);
|
||||
painter.setPen(Qt::black);
|
||||
painter.drawText(0, 0, mCachedWidth, mLineHeight, Qt::AlignHCenter | Qt::AlignVCenter, "0x" + QString::number(mAddress, 16).toUpper());
|
||||
|
||||
// Block instructions
|
||||
for(QList<RichTextPainter::CustomRichText_t> &richText : mRichTextVector)
|
||||
{
|
||||
RichTextPainter::paintRichText(&painter, x, y, mCachedWidth, mLineHeight, 0, &richText, QFontMetrics(this->mFont).width(QChar(' ')));
|
||||
|
||||
if(mHighlightInstructionAt == i)
|
||||
painter.fillRect(0, y, mCachedWidth, mLineHeight, QBrush(QColor(0, 0, 0, 150)));
|
||||
|
||||
y += mLineHeight + mLineSpacingY;
|
||||
i++;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
dsint GraphNode::getInstructionIndexAtPos(const QPoint &pos) const
|
||||
{
|
||||
// Gets the instruction index at the cursor position
|
||||
duint instructionIndex = -1;
|
||||
for(duint i = 0; i < mInstructionsVector.size(); i++)
|
||||
{
|
||||
dsint currentInstructionMinHeight = (i+1) * (mLineHeight + mLineSpacingY) + (mSpacingY/2);
|
||||
dsint currentInstructionMaxHeight = (i+2) * (mLineHeight+mLineSpacingY) + (mSpacingY/2);
|
||||
|
||||
if(pos.y() >= currentInstructionMinHeight && pos.y() <= currentInstructionMaxHeight)
|
||||
{
|
||||
instructionIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return instructionIndex;
|
||||
}
|
||||
|
||||
bool GraphNode::eventFilter(QObject *object, QEvent *event)
|
||||
{
|
||||
// Mouse click
|
||||
if(event->type() == QEvent::MouseButtonPress)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
if(mouseEvent->button() != Qt::LeftButton)
|
||||
return true;
|
||||
|
||||
duint clickedInstructionIndex = getInstructionIndexAtPos(mouseEvent->pos());
|
||||
|
||||
// No instruction clicked
|
||||
if(clickedInstructionIndex == -1)
|
||||
return true;
|
||||
|
||||
Instruction_t clickedInstruction = mInstructionsVector.at(clickedInstructionIndex);
|
||||
if(clickedInstruction.branchDestination != 0)
|
||||
emit drawGraphAt(clickedInstruction.branchDestination);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Mouse move
|
||||
else if(event->type() == QEvent::MouseMove)
|
||||
{
|
||||
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
||||
mHighlightInstructionAt = getInstructionIndexAtPos(mouseEvent->pos());
|
||||
repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
// Leaving widget area
|
||||
else if(event->type() == QEvent::Leave)
|
||||
{
|
||||
mHighlightInstructionAt = -1;
|
||||
repaint();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void GraphNode::updateTokensVector()
|
||||
{
|
||||
for(duint i=0; i < mInstructionsVector.size(); i++)
|
||||
{
|
||||
mTokensVector.push_back(mInstructionsVector[i].tokens);
|
||||
}
|
||||
|
||||
updateCache();
|
||||
updateRichText();
|
||||
}
|
||||
|
||||
void GraphNode::setInstructionsVector(const std::vector<Instruction_t> &instructionsVector)
|
||||
{
|
||||
mInstructionsVector = instructionsVector;
|
||||
}
|
||||
|
||||
void GraphNode::updateCache()
|
||||
{
|
||||
QString maxInstruction = getLongestInstruction();
|
||||
|
||||
QFontMetrics metrics(this->mFont);
|
||||
mCachedWidth = metrics.width(maxInstruction) + mSpacingX;
|
||||
mCachedHeight =((metrics.height() + mLineSpacingY) * mInstructionsVector.size()) + metrics.height() + mSpacingY; // +metrics.height() => for block address line
|
||||
mLineHeight = metrics.height();
|
||||
}
|
||||
|
||||
void GraphNode::updateRichText()
|
||||
{
|
||||
for(CapstoneTokenizer::InstructionToken &token : mTokensVector)
|
||||
{
|
||||
QList<RichTextPainter::CustomRichText_t> richText;
|
||||
CapstoneTokenizer::TokenToRichText(token, richText, 0);
|
||||
mRichTextVector.push_back(richText);
|
||||
}
|
||||
}
|
||||
|
||||
QString GraphNode::getLongestInstruction()
|
||||
{
|
||||
dsint maxInstructionLength = 0;
|
||||
QString maxInstruction = "";
|
||||
|
||||
for(CapstoneTokenizer::InstructionToken &token : mTokensVector)
|
||||
{
|
||||
dsint currentInstructionLength = 0;
|
||||
QString currentInstruction = "";
|
||||
for(CapstoneTokenizer::SingleToken &singleToken : token.tokens)
|
||||
{
|
||||
currentInstructionLength += singleToken.text.length();
|
||||
currentInstruction += singleToken.text;
|
||||
}
|
||||
|
||||
if(currentInstructionLength > maxInstructionLength)
|
||||
{
|
||||
maxInstructionLength = currentInstructionLength;
|
||||
maxInstruction = currentInstruction;
|
||||
}
|
||||
}
|
||||
|
||||
return maxInstruction;
|
||||
}
|
||||
|
||||
duint GraphNode::address()
|
||||
{
|
||||
return mAddress;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue