mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-31 00:35:05 +00:00
GraphView fixes (#214)
This commit is contained in:
parent
273c87eaba
commit
ce2557ccbe
@ -102,6 +102,8 @@ Cutter is developed on OS X, Linux and Windows. The first release for users will
|
||||
| + | Zoom in |
|
||||
| - | Zoom out |
|
||||
| = | Reset zoom |
|
||||
| J | Next instruction |
|
||||
| K | Previous instruction |
|
||||
|
||||
|
||||
## Help
|
||||
|
@ -17,7 +17,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
|
||||
mFontMetrics(nullptr),
|
||||
mMenu(new DisassemblyContextMenu(this))
|
||||
{
|
||||
this->highlight_token = nullptr;
|
||||
highlight_token = nullptr;
|
||||
// Signals that require a refresh all
|
||||
connect(Core(), SIGNAL(refreshAll()), this, SLOT(refreshView()));
|
||||
connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshView()));
|
||||
@ -31,9 +31,9 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
|
||||
connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(onSeekChanged(RVA)));
|
||||
|
||||
// Space to switch to disassembly
|
||||
QShortcut *disassemblyShortcut = new QShortcut(QKeySequence(Qt::Key_Space), this);
|
||||
disassemblyShortcut->setContext(Qt::WidgetShortcut);
|
||||
connect(disassemblyShortcut, &QShortcut::activated, this, []{
|
||||
QShortcut *shortcut_disassembly = new QShortcut(QKeySequence(Qt::Key_Space), this);
|
||||
shortcut_disassembly->setContext(Qt::WidgetShortcut);
|
||||
connect(shortcut_disassembly, &QShortcut::activated, this, []{
|
||||
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly);
|
||||
Core()->triggerRaisePrioritizedMemoryWidget();
|
||||
});
|
||||
@ -61,15 +61,39 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent)
|
||||
shortcut_take_false->setContext(Qt::WidgetShortcut);
|
||||
connect(shortcut_take_false, SIGNAL(activated()), this, SLOT(takeFalse()));
|
||||
|
||||
// Navigation shortcuts
|
||||
QShortcut *shortcut_next_instr = new QShortcut(QKeySequence(Qt::Key_J), this);
|
||||
shortcut_next_instr->setContext(Qt::WidgetShortcut);
|
||||
connect(shortcut_next_instr, SIGNAL(activated()), this, SLOT(nextInstr()));
|
||||
QShortcut *shortcut_prev_instr = new QShortcut(QKeySequence(Qt::Key_K), this);
|
||||
shortcut_prev_instr->setContext(Qt::WidgetShortcut);
|
||||
connect(shortcut_prev_instr, SIGNAL(activated()), this, SLOT(prevInstr()));
|
||||
shortcuts.append(shortcut_disassembly);
|
||||
shortcuts.append(shortcut_escape);
|
||||
shortcuts.append(shortcut_zoom_in);
|
||||
shortcuts.append(shortcut_zoom_out);
|
||||
shortcuts.append(shortcut_zoom_reset);
|
||||
shortcuts.append(shortcut_next_instr);
|
||||
shortcuts.append(shortcut_prev_instr);
|
||||
|
||||
|
||||
initFont();
|
||||
colorsUpdatedSlot();
|
||||
}
|
||||
|
||||
DisassemblerGraphView::~DisassemblerGraphView()
|
||||
{
|
||||
for(QShortcut *shortcut : shortcuts)
|
||||
{
|
||||
delete shortcut;
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::refreshView()
|
||||
{
|
||||
initFont();
|
||||
loadCurrentGraph();
|
||||
this->viewport()->update();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::loadCurrentGraph()
|
||||
@ -78,7 +102,7 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
QJsonArray functions = functionsDoc.array();
|
||||
|
||||
disassembly_blocks.clear();
|
||||
this->blocks.clear();
|
||||
blocks.clear();
|
||||
|
||||
Analysis anal;
|
||||
anal.ready = true;
|
||||
@ -95,7 +119,7 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
{
|
||||
windowTitle += " (" + funcName + ")";
|
||||
}
|
||||
this->parentWidget()->setWindowTitle(windowTitle);
|
||||
parentWidget()->setWindowTitle(windowTitle);
|
||||
|
||||
RVA entry = func["offset"].toVariant().toULongLong();
|
||||
|
||||
@ -157,7 +181,13 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
if(func["blocks"].toArray().size() > 0)
|
||||
{
|
||||
computeGraph(entry);
|
||||
this->viewport()->update();
|
||||
viewport()->update();
|
||||
|
||||
if(first_draw)
|
||||
{
|
||||
showBlock(blocks[entry]);
|
||||
first_draw = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,20 +217,20 @@ void DisassemblerGraphView::prepareGraphNode(GraphBlock &block)
|
||||
height += 1;
|
||||
}
|
||||
}
|
||||
int extra = 4 * this->charWidth + 4;
|
||||
block.width = width + extra + this->charWidth;
|
||||
block.height = (height * this->charHeight) + extra;
|
||||
int extra = 4 * charWidth + 4;
|
||||
block.width = width + extra + charWidth;
|
||||
block.height = (height * charHeight) + extra;
|
||||
}
|
||||
|
||||
|
||||
void DisassemblerGraphView::initFont()
|
||||
{
|
||||
setFont(Config()->getFont());
|
||||
QFontMetricsF metrics(this->font());
|
||||
this->baseline = int(metrics.ascent());
|
||||
this->charWidth = metrics.width('X');
|
||||
this->charHeight = metrics.height();
|
||||
this->charOffset = 0;
|
||||
QFontMetricsF metrics(font());
|
||||
baseline = int(metrics.ascent());
|
||||
charWidth = metrics.width('X');
|
||||
charHeight = metrics.height();
|
||||
charOffset = 0;
|
||||
if(mFontMetrics)
|
||||
delete mFontMetrics;
|
||||
mFontMetrics = new CachedFontMetrics(this, font());
|
||||
@ -257,7 +287,7 @@ void DisassemblerGraphView::drawBlock(QPainter & p, GraphView::GraphBlock &block
|
||||
// Draw different background for selected instruction
|
||||
if(selected_instruction != RVA_INVALID)
|
||||
{
|
||||
int y = block.y + (2 * this->charWidth) + (db.header_text.lines.size() * this->charHeight);
|
||||
int y = block.y + (2 * charWidth) + (db.header_text.lines.size() * charHeight);
|
||||
for(Instr & instr : db.instrs)
|
||||
{
|
||||
auto selected = instr.addr == selected_instruction;
|
||||
@ -265,13 +295,13 @@ void DisassemblerGraphView::drawBlock(QPainter & p, GraphView::GraphBlock &block
|
||||
auto traceCount = 0;
|
||||
if(selected && traceCount)
|
||||
{
|
||||
p.fillRect(QRect(block.x + this->charWidth, y, block.width - (10 + 2 * this->charWidth),
|
||||
int(instr.text.lines.size()) * this->charHeight), disassemblyTracedSelectionColor);
|
||||
p.fillRect(QRect(block.x + charWidth, y, block.width - (10 + 2 * charWidth),
|
||||
int(instr.text.lines.size()) * charHeight), disassemblyTracedSelectionColor);
|
||||
}
|
||||
else if(selected)
|
||||
{
|
||||
p.fillRect(QRect(block.x + this->charWidth, y, block.width - (10 + 2 * this->charWidth),
|
||||
int(instr.text.lines.size()) * this->charHeight), disassemblySelectionColor);
|
||||
p.fillRect(QRect(block.x + charWidth, y, block.width - (10 + 2 * charWidth),
|
||||
int(instr.text.lines.size()) * charHeight), disassemblySelectionColor);
|
||||
}
|
||||
else if(traceCount)
|
||||
{
|
||||
@ -285,40 +315,40 @@ void DisassemblerGraphView::drawBlock(QPainter & p, GraphView::GraphBlock &block
|
||||
if(disassemblyTracedColor.blue() > 160)
|
||||
colorDiff *= -1;
|
||||
|
||||
p.fillRect(QRect(block.x + this->charWidth, y, block.width - (10 + 2 * this->charWidth), int(instr.text.lines.size()) * this->charHeight),
|
||||
p.fillRect(QRect(block.x + charWidth, y, block.width - (10 + 2 * charWidth), int(instr.text.lines.size()) * charHeight),
|
||||
QColor(disassemblyTracedColor.red(),
|
||||
disassemblyTracedColor.green(),
|
||||
std::max(0, std::min(256, disassemblyTracedColor.blue() + colorDiff))));
|
||||
}
|
||||
y += int(instr.text.lines.size()) * this->charHeight;
|
||||
y += int(instr.text.lines.size()) * charHeight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Render node text
|
||||
auto x = block.x + (2 * this->charWidth);
|
||||
int y = block.y + (2 * this->charWidth);
|
||||
auto x = block.x + (2 * charWidth);
|
||||
int y = block.y + (2 * charWidth);
|
||||
for(auto & line : db.header_text.lines)
|
||||
{
|
||||
RichTextPainter::paintRichText(&p, x, y, block.width, this->charHeight, 0, line, mFontMetrics);
|
||||
y += this->charHeight;
|
||||
RichTextPainter::paintRichText(&p, x, y, block.width, charHeight, 0, line, mFontMetrics);
|
||||
y += charHeight;
|
||||
}
|
||||
for(Instr & instr : db.instrs)
|
||||
{
|
||||
for(auto & line : instr.text.lines)
|
||||
{
|
||||
int rectSize = qRound(this->charWidth);
|
||||
int rectSize = qRound(charWidth);
|
||||
if(rectSize % 2)
|
||||
{
|
||||
rectSize++;
|
||||
}
|
||||
// Assume charWidth <= charHeight
|
||||
QRectF bpRect(x - rectSize / 3.0, y + (this->charHeight - rectSize) / 2.0, rectSize, rectSize);
|
||||
QRectF bpRect(x - rectSize / 3.0, y + (charHeight - rectSize) / 2.0, rectSize, rectSize);
|
||||
|
||||
// TODO: Breakpoint/Cip stuff
|
||||
|
||||
RichTextPainter::paintRichText(&p, x + this->charWidth, y, block.width - this->charWidth, this->charHeight, 0, line, mFontMetrics);
|
||||
y += this->charHeight;
|
||||
RichTextPainter::paintRichText(&p, x + charWidth, y, block.width - charWidth, charHeight, 0, line, mFontMetrics);
|
||||
y += charHeight;
|
||||
|
||||
}
|
||||
}
|
||||
@ -348,7 +378,13 @@ GraphView::EdgeConfiguration DisassemblerGraphView::edgeConfiguration(GraphView:
|
||||
RVA DisassemblerGraphView::getInstrForMouseEvent(GraphBlock &block, QPoint* point)
|
||||
{
|
||||
DisassemblyBlock &db = disassembly_blocks[block.entry];
|
||||
int mouse_row = ((point->y()-(2*this->charWidth)) / this->charHeight);
|
||||
|
||||
// Remove header and margin
|
||||
int off_y = (2 * charWidth) + (db.header_text.lines.size() * charHeight);
|
||||
// Get mouse coordinate over the actual text
|
||||
int text_point_y = point->y() - off_y;
|
||||
int mouse_row = text_point_y / charHeight;
|
||||
|
||||
int cur_row = db.header_text.lines.size();
|
||||
if (mouse_row < cur_row)
|
||||
{
|
||||
@ -389,7 +425,7 @@ void DisassemblerGraphView::colorsUpdatedSlot()
|
||||
|
||||
void DisassemblerGraphView::fontsUpdatedSlot()
|
||||
{
|
||||
this->initFont();
|
||||
initFont();
|
||||
refreshView();
|
||||
}
|
||||
|
||||
@ -440,26 +476,26 @@ void DisassemblerGraphView::onSeekChanged(RVA addr)
|
||||
void DisassemblerGraphView::zoomIn()
|
||||
{
|
||||
current_scale += 0.1;
|
||||
auto areaSize = this->viewport()->size();
|
||||
this->adjustSize(areaSize.width(), areaSize.height());
|
||||
this->viewport()->update();
|
||||
auto areaSize = viewport()->size();
|
||||
adjustSize(areaSize.width(), areaSize.height());
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::zoomOut()
|
||||
{
|
||||
current_scale -= 0.1;
|
||||
current_scale = std::max(current_scale, 0.3);
|
||||
auto areaSize = this->viewport()->size();
|
||||
this->adjustSize(areaSize.width(), areaSize.height());
|
||||
this->viewport()->update();
|
||||
auto areaSize = viewport()->size();
|
||||
adjustSize(areaSize.width(), areaSize.height());
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::zoomReset()
|
||||
{
|
||||
current_scale = 1.0;
|
||||
auto areaSize = this->viewport()->size();
|
||||
this->adjustSize(areaSize.width(), areaSize.height());
|
||||
this->viewport()->update();
|
||||
auto areaSize = viewport()->size();
|
||||
adjustSize(areaSize.width(), areaSize.height());
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::takeTrue()
|
||||
@ -488,13 +524,52 @@ void DisassemblerGraphView::takeFalse()
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::seekInstruction(bool previous_instr)
|
||||
{
|
||||
RVA addr = Core()->getOffset();
|
||||
DisassemblyBlock *db = blockForAddress(addr);
|
||||
if(!db)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for(size_t i=0; i < db->instrs.size(); i++)
|
||||
{
|
||||
Instr &instr = db->instrs[i];
|
||||
if(!((instr.addr <= addr) && (addr <= instr.addr + instr.size)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found the instructon. Check if a next one exists
|
||||
if(!previous_instr && (i < db->instrs.size()-1))
|
||||
{
|
||||
seek(db->instrs[i+1].addr, true);
|
||||
}
|
||||
else if(previous_instr && (i > 0))
|
||||
{
|
||||
seek(db->instrs[i-1].addr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::nextInstr()
|
||||
{
|
||||
seekInstruction(false);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::prevInstr()
|
||||
{
|
||||
seekInstruction(true);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::seek(RVA addr, bool update_viewport)
|
||||
{
|
||||
sent_seek = true;
|
||||
Core()->seek(addr);
|
||||
if(update_viewport)
|
||||
{
|
||||
this->viewport()->update();
|
||||
viewport()->update();
|
||||
}
|
||||
}
|
||||
|
||||
@ -505,11 +580,10 @@ void DisassemblerGraphView::seekPrev()
|
||||
|
||||
void DisassemblerGraphView::blockClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos)
|
||||
{
|
||||
RVA instr = this->getInstrForMouseEvent(block, &pos);
|
||||
RVA instr = getInstrForMouseEvent(block, &pos);
|
||||
if(instr == RVA_INVALID)
|
||||
{
|
||||
return;
|
||||
//
|
||||
}
|
||||
|
||||
seek(instr, true);
|
||||
@ -521,6 +595,23 @@ void DisassemblerGraphView::blockClicked(GraphView::GraphBlock &block, QMouseEve
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::blockDoubleClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos)
|
||||
{
|
||||
RVA instr = getInstrForMouseEvent(block, &pos);
|
||||
if(instr == RVA_INVALID)
|
||||
{
|
||||
return;
|
||||
}
|
||||
QList<XrefDescription> refs = Core()->getXRefs(instr, false, false);
|
||||
if (refs.length()) {
|
||||
sent_seek = false;
|
||||
Core()->seek(refs.at(0).to);
|
||||
}
|
||||
if (refs.length() > 1) {
|
||||
qWarning() << "Too many references here. Weird behaviour expected.";
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::blockTransitionedTo(GraphView::GraphBlock *to)
|
||||
{
|
||||
if(transition_dont_seek)
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPainter>
|
||||
#include <QShortcut>
|
||||
|
||||
#include "widgets/GraphView.h"
|
||||
#include "menus/DisassemblyContextMenu.h"
|
||||
@ -136,9 +137,11 @@ class DisassemblerGraphView : public GraphView
|
||||
|
||||
public:
|
||||
DisassemblerGraphView(QWidget *parent);
|
||||
~DisassemblerGraphView();
|
||||
std::unordered_map<ut64, DisassemblyBlock> disassembly_blocks;
|
||||
virtual void drawBlock(QPainter & p, GraphView::GraphBlock &block) override;
|
||||
virtual void blockClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos) override;
|
||||
virtual void blockDoubleClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos) override;
|
||||
virtual GraphView::EdgeConfiguration edgeConfiguration(GraphView::GraphBlock &from, GraphView::GraphBlock *to) override;
|
||||
virtual void blockTransitionedTo(GraphView::GraphBlock *to) override;
|
||||
|
||||
@ -157,10 +160,14 @@ public slots:
|
||||
|
||||
void takeTrue();
|
||||
void takeFalse();
|
||||
|
||||
void nextInstr();
|
||||
void prevInstr();
|
||||
private slots:
|
||||
void seekPrev();
|
||||
|
||||
private:
|
||||
bool first_draw = true;
|
||||
bool transition_dont_seek = false;
|
||||
bool sent_seek = false;
|
||||
|
||||
@ -168,7 +175,7 @@ private:
|
||||
// Font data
|
||||
CachedFontMetrics* mFontMetrics;
|
||||
qreal charWidth;
|
||||
qreal charHeight;
|
||||
int charHeight;
|
||||
int charOffset;
|
||||
int baseline;
|
||||
|
||||
@ -179,6 +186,9 @@ private:
|
||||
RVA getInstrForMouseEvent(GraphBlock &block, QPoint* point);
|
||||
DisassemblyBlock *blockForAddress(RVA addr);
|
||||
void seek(RVA addr, bool update_viewport=true);
|
||||
void seekInstruction(bool previous_instr);
|
||||
|
||||
QList<QShortcut*> shortcuts;
|
||||
|
||||
QColor disassemblyBackgroundColor;
|
||||
QColor disassemblySelectedBackgroundColor;
|
||||
|
@ -9,12 +9,12 @@
|
||||
GraphView::GraphView(QWidget *parent)
|
||||
: QAbstractScrollArea(parent)
|
||||
{
|
||||
this->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
this->horizontalScrollBar()->setSingleStep(this->charWidth);
|
||||
this->verticalScrollBar()->setSingleStep(this->charWidth);
|
||||
QSize areaSize = this->viewport()->size();
|
||||
this->adjustSize(areaSize.width(), areaSize.height());
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
horizontalScrollBar()->setSingleStep(charWidth);
|
||||
verticalScrollBar()->setSingleStep(charWidth);
|
||||
QSize areaSize = viewport()->size();
|
||||
adjustSize(areaSize.width(), areaSize.height());
|
||||
}
|
||||
|
||||
GraphView::~GraphView()
|
||||
@ -53,6 +53,14 @@ void GraphView::blockClicked(GraphView::GraphBlock &block, QMouseEvent *event, Q
|
||||
qWarning() << "Block clicked not overridden!";
|
||||
}
|
||||
|
||||
void GraphView::blockDoubleClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos)
|
||||
{
|
||||
Q_UNUSED(block);
|
||||
Q_UNUSED(event);
|
||||
Q_UNUSED(pos);
|
||||
qWarning() << "Block double clicked not overridden!";
|
||||
}
|
||||
|
||||
void GraphView::blockTransitionedTo(GraphView::GraphBlock *to)
|
||||
{
|
||||
Q_UNUSED(to);
|
||||
@ -83,9 +91,9 @@ void GraphView::adjustSize(int new_width, int new_height)
|
||||
|
||||
//Update scroll bar information
|
||||
horizontalScrollBar()->setPageStep(new_width);
|
||||
horizontalScrollBar()->setRange(0, this->width - (new_width/current_scale));
|
||||
horizontalScrollBar()->setRange(0, width - (new_width/current_scale));
|
||||
verticalScrollBar()->setPageStep(new_height);
|
||||
verticalScrollBar()->setRange(0, this->height - (new_height/current_scale));
|
||||
verticalScrollBar()->setRange(0, height - (new_height/current_scale));
|
||||
horizontalScrollBar()->setValue((int)((double)horizontalScrollBar()->maximum() * hfactor));
|
||||
verticalScrollBar()->setValue((int)((double)verticalScrollBar()->maximum() * vfactor));
|
||||
}
|
||||
@ -93,15 +101,15 @@ void GraphView::adjustSize(int new_width, int new_height)
|
||||
// This calculates the full graph starting at block entry.
|
||||
void GraphView::computeGraph(ut64 entry)
|
||||
{
|
||||
QSize areaSize = this->viewport()->size();
|
||||
QSize areaSize = viewport()->size();
|
||||
|
||||
// Populate incoming lists
|
||||
for(auto &blockIt : this->blocks)
|
||||
for(auto &blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
for(auto & edge : block.exits)
|
||||
{
|
||||
this->blocks[edge].incoming.push_back(block.entry);
|
||||
blocks[edge].incoming.push_back(block.entry);
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,7 +127,7 @@ void GraphView::computeGraph(ut64 entry)
|
||||
// Pick nodes with single entrypoints
|
||||
while(!queue.empty())
|
||||
{
|
||||
GraphBlock &block = this->blocks[queue.front()];
|
||||
GraphBlock &block = blocks[queue.front()];
|
||||
queue.pop();
|
||||
block_order.push_back(block.entry);
|
||||
for(ut64 edge : block.exits)
|
||||
@ -131,22 +139,22 @@ void GraphView::computeGraph(ut64 entry)
|
||||
}
|
||||
|
||||
// Some edges might not be available
|
||||
if(!this->blocks.count(edge))
|
||||
if(!blocks.count(edge))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// If this node has no other incoming edges, add it to the graph layout
|
||||
if(this->blocks[edge].incoming.size() == 1)
|
||||
if(blocks[edge].incoming.size() == 1)
|
||||
{
|
||||
removeFromVec(this->blocks[edge].incoming, block.entry);
|
||||
removeFromVec(blocks[edge].incoming, block.entry);
|
||||
block.new_exits.push_back(edge);
|
||||
queue.push(this->blocks[edge].entry);
|
||||
queue.push(blocks[edge].entry);
|
||||
visited.insert(edge);
|
||||
changed = true;
|
||||
} else {
|
||||
// Remove from incoming edges
|
||||
removeFromVec(this->blocks[edge].incoming, block.entry);
|
||||
removeFromVec(blocks[edge].incoming, block.entry);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -155,7 +163,7 @@ void GraphView::computeGraph(ut64 entry)
|
||||
ut64 best = 0;
|
||||
int best_edges;
|
||||
ut64 best_parent;
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
// Skip blocks we haven't visited yet
|
||||
@ -170,24 +178,24 @@ void GraphView::computeGraph(ut64 entry)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if(!this->blocks.count(edge))
|
||||
if(!blocks.count(edge))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
// find best edge
|
||||
if((best == 0) || ((int)this->blocks[edge].incoming.size() < best_edges) || (
|
||||
((int)this->blocks[edge].incoming.size() == best_edges) && (edge < best)))
|
||||
if((best == 0) || ((int)blocks[edge].incoming.size() < best_edges) || (
|
||||
((int)blocks[edge].incoming.size() == best_edges) && (edge < best)))
|
||||
{
|
||||
best = edge;
|
||||
best_edges = this->blocks[edge].incoming.size();
|
||||
best_edges = blocks[edge].incoming.size();
|
||||
best_parent = block.entry;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(best != 0)
|
||||
{
|
||||
GraphBlock &best_parentb = this->blocks[best_parent];
|
||||
removeFromVec(this->blocks[best].incoming, best_parentb.entry);
|
||||
GraphBlock &best_parentb = blocks[best_parent];
|
||||
removeFromVec(blocks[best].incoming, best_parentb.entry);
|
||||
best_parentb.new_exits.push_back(best);
|
||||
visited.insert(best);
|
||||
queue.push(best);
|
||||
@ -195,10 +203,10 @@ void GraphView::computeGraph(ut64 entry)
|
||||
}
|
||||
}
|
||||
|
||||
this->computeGraphLayout(this->blocks[entry]);
|
||||
computeGraphLayout(blocks[entry]);
|
||||
|
||||
// Prepare edge routing
|
||||
GraphBlock &entryb = this->blocks[entry];
|
||||
GraphBlock &entryb = blocks[entry];
|
||||
EdgesVector horiz_edges, vert_edges;
|
||||
horiz_edges.resize(entryb.row_count + 1);
|
||||
vert_edges.resize(entryb.row_count + 1);
|
||||
@ -216,7 +224,7 @@ void GraphView::computeGraph(ut64 entry)
|
||||
}
|
||||
}
|
||||
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
edge_valid[block.row][block.col + 1] = false;
|
||||
@ -229,8 +237,8 @@ void GraphView::computeGraph(ut64 entry)
|
||||
GraphBlock &start = block;
|
||||
for(ut64 edge : block.exits)
|
||||
{
|
||||
GraphBlock &end = this->blocks[edge];
|
||||
start.edges.push_back(this->routeEdge(horiz_edges, vert_edges, edge_valid, start, end, QColor(255, 0, 0)));
|
||||
GraphBlock &end = blocks[edge];
|
||||
start.edges.push_back(routeEdge(horiz_edges, vert_edges, edge_valid, start, end, QColor(255, 0, 0)));
|
||||
}
|
||||
}
|
||||
|
||||
@ -254,7 +262,7 @@ void GraphView::computeGraph(ut64 entry)
|
||||
std::vector<int> col_width, row_height;
|
||||
initVec(col_width, entryb.col_count + 1, 0);
|
||||
initVec(row_height, entryb.row_count + 1, 0);
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
if((int(block.width / 2)) > col_width[block.col])
|
||||
@ -269,47 +277,52 @@ void GraphView::computeGraph(ut64 entry)
|
||||
std::vector<int> col_x, row_y;
|
||||
initVec(col_x, entryb.col_count, 0);
|
||||
initVec(row_y, entryb.row_count, 0);
|
||||
initVec(this->col_edge_x, entryb.col_count + 1, 0);
|
||||
initVec(this->row_edge_y, entryb.row_count + 1, 0);
|
||||
int x = 16;
|
||||
initVec(col_edge_x, entryb.col_count + 1, 0);
|
||||
initVec(row_edge_y, entryb.row_count + 1, 0);
|
||||
int x = block_horizontal_margin * 2;
|
||||
for(int i = 0; i < entryb.col_count; i++)
|
||||
{
|
||||
this->col_edge_x[i] = x;
|
||||
x += 8 * col_edge_count[i];
|
||||
col_edge_x[i] = x;
|
||||
x += block_horizontal_margin * col_edge_count[i];
|
||||
col_x[i] = x;
|
||||
x += col_width[i];
|
||||
}
|
||||
int y = 16;
|
||||
int y = block_vertical_margin * 2;
|
||||
for(int i = 0; i < entryb.row_count; i++)
|
||||
{
|
||||
this->row_edge_y[i] = y;
|
||||
row_edge_y[i] = y;
|
||||
// TODO: The 1 when row_edge_count is 0 is not needed on the original.. not sure why it's required for us
|
||||
if(!row_edge_count[i])
|
||||
{
|
||||
row_edge_count[i] = 1;
|
||||
}
|
||||
y += block_vertical_margin * row_edge_count[i];
|
||||
row_y[i] = y;
|
||||
y += row_height[i];
|
||||
}
|
||||
this->col_edge_x[entryb.col_count] = x;
|
||||
this->row_edge_y[entryb.row_count] = y;
|
||||
this->width = x + 16 + (8 * col_edge_count[entryb.col_count]);
|
||||
this->height = y + 16 + (8 * row_edge_count[entryb.row_count]);
|
||||
col_edge_x[entryb.col_count] = x;
|
||||
row_edge_y[entryb.row_count] = y;
|
||||
width = x + (block_horizontal_margin * 2) + (block_horizontal_margin * col_edge_count[entryb.col_count]);
|
||||
height = y + (block_vertical_margin * 2) + (block_vertical_margin * row_edge_count[entryb.row_count]);
|
||||
|
||||
//Compute node positions
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
block.x = int(
|
||||
(col_x[block.col] + col_width[block.col] + 4 * col_edge_count[block.col + 1]) - (block.width / 2));
|
||||
(col_x[block.col] + col_width[block.col] + ((block_horizontal_margin / 2) * col_edge_count[block.col + 1])) - (block.width / 2));
|
||||
if((block.x + block.width) > (
|
||||
col_x[block.col] + col_width[block.col] + col_width[block.col + 1] + 8 * col_edge_count[
|
||||
col_x[block.col] + col_width[block.col] + col_width[block.col + 1] + block_horizontal_margin * col_edge_count[
|
||||
block.col + 1]))
|
||||
{
|
||||
block.x = int((col_x[block.col] + col_width[block.col] + col_width[block.col + 1] + 8 * col_edge_count[
|
||||
block.x = int((col_x[block.col] + col_width[block.col] + col_width[block.col + 1] + block_horizontal_margin * col_edge_count[
|
||||
block.col + 1]) - block.width);
|
||||
}
|
||||
block.y = row_y[block.row];
|
||||
}
|
||||
|
||||
// Precompute coordinates for edges
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
|
||||
@ -318,7 +331,8 @@ void GraphView::computeGraph(ut64 entry)
|
||||
auto start = edge.points[0];
|
||||
auto start_col = start.col;
|
||||
auto last_index = edge.start_index;
|
||||
auto first_pt = QPoint(this->col_edge_x[start_col] + (8 * last_index) + 4,
|
||||
// This is the start point of the edge.
|
||||
auto first_pt = QPoint(col_edge_x[start_col] + (block_horizontal_margin * last_index) + (block_horizontal_margin / 2),
|
||||
block.y + block.height);
|
||||
auto last_pt = first_pt;
|
||||
QPolygonF pts;
|
||||
@ -333,9 +347,9 @@ void GraphView::computeGraph(ut64 entry)
|
||||
QPoint new_pt;
|
||||
// block_vertical_margin/2 gives the margin from block to the horizontal lines
|
||||
if(start_col == end_col)
|
||||
new_pt = QPoint(last_pt.x(), this->row_edge_y[end_row] + (8 * last_index) + (block_vertical_margin/2));
|
||||
new_pt = QPoint(last_pt.x(), row_edge_y[end_row] + (block_vertical_margin * last_index) + (block_vertical_margin/2));
|
||||
else
|
||||
new_pt = QPoint(this->col_edge_x[end_col] + (8 * last_index) + 4, last_pt.y());
|
||||
new_pt = QPoint(col_edge_x[end_col] + (block_horizontal_margin * last_index) + (block_horizontal_margin/2), last_pt.y());
|
||||
pts.push_back(new_pt);
|
||||
last_pt = new_pt;
|
||||
start_col = end_col;
|
||||
@ -355,6 +369,8 @@ void GraphView::computeGraph(ut64 entry)
|
||||
pts.append(first_pt);
|
||||
edge.arrow_start = pts;
|
||||
}
|
||||
if(ec.end_arrow)
|
||||
{
|
||||
pts.clear();
|
||||
pts.append(QPoint(new_pt.x() - 3, new_pt.y() - 6));
|
||||
pts.append(QPoint(new_pt.x() + 3, new_pt.y() - 6));
|
||||
@ -362,35 +378,55 @@ void GraphView::computeGraph(ut64 entry)
|
||||
edge.arrow_end = pts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this->ready = true;
|
||||
ready = true;
|
||||
|
||||
this->viewport()->update();
|
||||
areaSize = this->viewport()->size();
|
||||
this->adjustSize(areaSize.width(), areaSize.height());
|
||||
viewport()->update();
|
||||
areaSize = viewport()->size();
|
||||
adjustSize(areaSize.width(), areaSize.height());
|
||||
}
|
||||
|
||||
void GraphView::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
QPainter p(this->viewport());
|
||||
int render_offset_x = -this->horizontalScrollBar()->value() * current_scale;
|
||||
int render_offset_y = -this->verticalScrollBar()->value() * current_scale;
|
||||
int render_width = this->viewport()->size().width() / current_scale;
|
||||
int render_height = this->viewport()->size().height() / current_scale;
|
||||
QPainter p(viewport());
|
||||
int render_offset_x = -horizontalScrollBar()->value() * current_scale;
|
||||
int render_offset_y = -verticalScrollBar()->value() * current_scale;
|
||||
int render_width = viewport()->size().width() / current_scale;
|
||||
int render_height = viewport()->size().height() / current_scale;
|
||||
|
||||
// Do we have scrollbars?
|
||||
bool hscrollbar = horizontalScrollBar()->pageStep() < width;
|
||||
bool vscrollbar = verticalScrollBar()->pageStep() < height;
|
||||
|
||||
// Draw background
|
||||
QRect viewportRect(this->viewport()->rect().topLeft(), this->viewport()->rect().bottomRight() - QPoint(1, 1));
|
||||
QRect viewportRect(viewport()->rect().topLeft(), viewport()->rect().bottomRight() - QPoint(1, 1));
|
||||
p.setBrush(backgroundColor);
|
||||
p.drawRect(viewportRect);
|
||||
p.setBrush(Qt::black);
|
||||
|
||||
unscrolled_render_offset_x = 0;
|
||||
unscrolled_render_offset_y = 0;
|
||||
|
||||
// We do not have a scrollbar on this axis, so we center the view
|
||||
if(!hscrollbar)
|
||||
{
|
||||
unscrolled_render_offset_x = (viewport()->size().width() - (width * current_scale)) / 2;
|
||||
render_offset_x += unscrolled_render_offset_x;
|
||||
}
|
||||
if(!vscrollbar)
|
||||
{
|
||||
unscrolled_render_offset_y = (viewport()->size().height() - (height * current_scale)) / 2;
|
||||
render_offset_y += unscrolled_render_offset_y;
|
||||
}
|
||||
|
||||
p.translate(render_offset_x, render_offset_y);
|
||||
p.scale(current_scale, current_scale);
|
||||
|
||||
|
||||
// Draw blocks
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
|
||||
@ -429,7 +465,6 @@ void GraphView::paintEvent(QPaintEvent* event)
|
||||
p.drawConvexPolygon(edge.arrow_end);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -446,34 +481,34 @@ void GraphView::computeGraphLayout(GraphBlock &block)
|
||||
for(size_t i = 0; i < block.new_exits.size(); i++)
|
||||
{
|
||||
ut64 edge = block.new_exits[i];
|
||||
GraphBlock &edgeb = this->blocks[edge];
|
||||
this->computeGraphLayout(edgeb);
|
||||
GraphBlock &edgeb = blocks[edge];
|
||||
computeGraphLayout(edgeb);
|
||||
row_count = std::max(edgeb.row_count + 1, row_count);
|
||||
childColumn = edgeb.col;
|
||||
}
|
||||
|
||||
if(this->layoutType != LayoutType::Wide && block.new_exits.size() == 2)
|
||||
if(layoutType != LayoutType::Wide && block.new_exits.size() == 2)
|
||||
{
|
||||
GraphBlock &left = this->blocks[block.new_exits[0]];
|
||||
GraphBlock &right= this->blocks[block.new_exits[1]];
|
||||
GraphBlock &left = blocks[block.new_exits[0]];
|
||||
GraphBlock &right= blocks[block.new_exits[1]];
|
||||
if(left.new_exits.size() == 0)
|
||||
{
|
||||
left.col = right.col - 2;
|
||||
int add = left.col < 0 ? - left.col : 0;
|
||||
this->adjustGraphLayout(right, add, 1);
|
||||
this->adjustGraphLayout(left, add, 1);
|
||||
adjustGraphLayout(right, add, 1);
|
||||
adjustGraphLayout(left, add, 1);
|
||||
col = right.col_count + add;
|
||||
}
|
||||
else if(right.new_exits.size() == 0)
|
||||
{
|
||||
this->adjustGraphLayout(left, 0, 1);
|
||||
this->adjustGraphLayout(right, left.col + 2, 1);
|
||||
adjustGraphLayout(left, 0, 1);
|
||||
adjustGraphLayout(right, left.col + 2, 1);
|
||||
col = std::max(left.col_count, right.col + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
this->adjustGraphLayout(left, 0, 1);
|
||||
this->adjustGraphLayout(right, left.col_count, 1);
|
||||
adjustGraphLayout(left, 0, 1);
|
||||
adjustGraphLayout(right, left.col_count, 1);
|
||||
col = left.col_count + right.col_count;
|
||||
}
|
||||
block.col_count = std::max(2, col);
|
||||
@ -490,8 +525,8 @@ void GraphView::computeGraphLayout(GraphBlock &block)
|
||||
{
|
||||
for(ut64 edge : block.new_exits)
|
||||
{
|
||||
this->adjustGraphLayout(this->blocks[edge], col, 1);
|
||||
col += this->blocks[edge].col_count;
|
||||
adjustGraphLayout(blocks[edge], col, 1);
|
||||
col += blocks[edge].col_count;
|
||||
}
|
||||
if(col >= 2)
|
||||
{
|
||||
@ -536,11 +571,11 @@ GraphView::GraphEdge GraphView::routeEdge(EdgesVector & horiz_edges, EdgesVector
|
||||
int i = 0;
|
||||
while(true)
|
||||
{
|
||||
if(!this->isEdgeMarked(vert_edges, start.row + 1, start.col + 1, i))
|
||||
if(!isEdgeMarked(vert_edges, start.row + 1, start.col + 1, i))
|
||||
break;
|
||||
i += 1;
|
||||
}
|
||||
this->markEdge(vert_edges, start.row + 1, start.col + 1, i);
|
||||
markEdge(vert_edges, start.row + 1, start.col + 1, i);
|
||||
edge.addPoint(start.row + 1, start.col + 1);
|
||||
edge.start_index = i;
|
||||
bool horiz = false;
|
||||
@ -617,7 +652,7 @@ GraphView::GraphEdge GraphView::routeEdge(EdgesVector & horiz_edges, EdgesVector
|
||||
min_col = start.col + 1;
|
||||
max_col = col;
|
||||
}
|
||||
int index = this->findHorizEdgeIndex(horiz_edges, start.row + 1, min_col, max_col);
|
||||
int index = findHorizEdgeIndex(horiz_edges, start.row + 1, min_col, max_col);
|
||||
edge.addPoint(start.row + 1, col, index);
|
||||
horiz = true;
|
||||
}
|
||||
@ -626,8 +661,8 @@ GraphView::GraphEdge GraphView::routeEdge(EdgesVector & horiz_edges, EdgesVector
|
||||
{
|
||||
//Not in same row, need to generate a line for moving to the correct row
|
||||
if(col == (start.col + 1))
|
||||
this->markEdge(vert_edges, start.row + 1, start.col + 1, i, false);
|
||||
int index = this->findVertEdgeIndex(vert_edges, col, min_row, max_row);
|
||||
markEdge(vert_edges, start.row + 1, start.col + 1, i, false);
|
||||
int index = findVertEdgeIndex(vert_edges, col, min_row, max_row);
|
||||
if(col == (start.col + 1))
|
||||
edge.start_index = index;
|
||||
edge.addPoint(end.row, col, index);
|
||||
@ -648,7 +683,7 @@ GraphView::GraphEdge GraphView::routeEdge(EdgesVector & horiz_edges, EdgesVector
|
||||
min_col = end.col + 1;
|
||||
max_col = col;
|
||||
}
|
||||
int index = this->findHorizEdgeIndex(horiz_edges, end.row, min_col, max_col);
|
||||
int index = findHorizEdgeIndex(horiz_edges, end.row, min_col, max_col);
|
||||
edge.addPoint(end.row, end.col + 1, index);
|
||||
horiz = true;
|
||||
}
|
||||
@ -656,7 +691,7 @@ GraphView::GraphEdge GraphView::routeEdge(EdgesVector & horiz_edges, EdgesVector
|
||||
//If last line was horizontal, choose the ending edge index for the incoming edge
|
||||
if(horiz)
|
||||
{
|
||||
int index = this->findVertEdgeIndex(vert_edges, end.col + 1, end.row, end.row);
|
||||
int index = findVertEdgeIndex(vert_edges, end.col + 1, end.row, end.row);
|
||||
edge.points[int(edge.points.size()) - 1].index = index;
|
||||
}
|
||||
|
||||
@ -683,7 +718,7 @@ int GraphView::findHorizEdgeIndex(EdgesVector & edges, int row, int min_col, int
|
||||
|
||||
//Mark chosen index as used
|
||||
for(int col = min_col; col < max_col + 1; col++)
|
||||
this->markEdge(edges, row, col, i);
|
||||
markEdge(edges, row, col, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -707,7 +742,7 @@ int GraphView::findVertEdgeIndex(EdgesVector & edges, int col, int min_row, int
|
||||
|
||||
//Mark chosen index as used
|
||||
for(int row = min_row; row < max_row + 1; row++)
|
||||
this->markEdge(edges, row, col, i);
|
||||
markEdge(edges, row, col, i);
|
||||
return i;
|
||||
}
|
||||
|
||||
@ -730,30 +765,30 @@ void GraphView::showBlock(GraphBlock *block, bool animated)
|
||||
|
||||
target_x = std::max(0, target_x);
|
||||
target_y = std::max(0, target_y);
|
||||
target_x = std::min(this->horizontalScrollBar()->maximum(), target_x);
|
||||
target_y = std::min(this->verticalScrollBar()->maximum(), target_y);
|
||||
target_x = std::min(horizontalScrollBar()->maximum(), target_x);
|
||||
target_y = std::min(verticalScrollBar()->maximum(), target_y);
|
||||
if(animated)
|
||||
{
|
||||
QPropertyAnimation *animation_x = new QPropertyAnimation(this->horizontalScrollBar(), "value");
|
||||
QPropertyAnimation *animation_x = new QPropertyAnimation(horizontalScrollBar(), "value");
|
||||
animation_x->setDuration(500);
|
||||
animation_x->setStartValue(this->horizontalScrollBar()->value());
|
||||
animation_x->setStartValue(horizontalScrollBar()->value());
|
||||
animation_x->setEndValue(target_x);
|
||||
animation_x->setEasingCurve(QEasingCurve::InOutQuad);
|
||||
animation_x->start();
|
||||
QPropertyAnimation *animation_y = new QPropertyAnimation(this->verticalScrollBar(), "value");
|
||||
QPropertyAnimation *animation_y = new QPropertyAnimation(verticalScrollBar(), "value");
|
||||
animation_y->setDuration(500);
|
||||
animation_y->setStartValue(this->verticalScrollBar()->value());
|
||||
animation_y->setStartValue(verticalScrollBar()->value());
|
||||
animation_y->setEndValue(target_y);
|
||||
animation_y->setEasingCurve(QEasingCurve::InOutQuad);
|
||||
animation_y->start();
|
||||
} else {
|
||||
this->horizontalScrollBar()->setValue(target_x);
|
||||
this->verticalScrollBar()->setValue(target_y);
|
||||
horizontalScrollBar()->setValue(target_x);
|
||||
verticalScrollBar()->setValue(target_y);
|
||||
}
|
||||
|
||||
blockTransitionedTo(block);
|
||||
|
||||
this->viewport()->update();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
void GraphView::adjustGraphLayout(GraphBlock &block, int col, int row)
|
||||
@ -762,18 +797,18 @@ void GraphView::adjustGraphLayout(GraphBlock &block, int col, int row)
|
||||
block.row += row;
|
||||
for(ut64 edge : block.new_exits)
|
||||
{
|
||||
this->adjustGraphLayout(this->blocks[edge], col, row);
|
||||
adjustGraphLayout(blocks[edge], col, row);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::addBlock(GraphView::GraphBlock block)
|
||||
{
|
||||
this->blocks[block.entry] = block;
|
||||
blocks[block.entry] = block;
|
||||
}
|
||||
|
||||
void GraphView::setEntry(ut64 e)
|
||||
{
|
||||
this->entry = e;
|
||||
entry = e;
|
||||
}
|
||||
|
||||
bool GraphView::checkPointClicked(QPointF &point, int x, int y, bool above_y)
|
||||
@ -782,7 +817,7 @@ bool GraphView::checkPointClicked(QPointF &point, int x, int y, bool above_y)
|
||||
if((point.x() - half_target_size < x) &&
|
||||
(point.y() - (above_y ? (2 * half_target_size) : 0) < y) &&
|
||||
(x < point.x() + half_target_size) &&
|
||||
(y < point.y() + (above_y ? 0 : (2 * half_target_size))))
|
||||
(y < point.y() + (above_y ? 0 : (3 * half_target_size))))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@ -798,8 +833,8 @@ void GraphView::resizeEvent(QResizeEvent* event)
|
||||
// Mouse events
|
||||
void GraphView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
int x = (event->pos().x() / current_scale) + horizontalScrollBar()->value();
|
||||
int y = (event->pos().y() / current_scale) + verticalScrollBar()->value();
|
||||
int x = ((event->pos().x() - unscrolled_render_offset_x) / current_scale) + horizontalScrollBar()->value();
|
||||
int y = ((event->pos().y() - unscrolled_render_offset_y) / current_scale) + verticalScrollBar()->value();
|
||||
|
||||
// Check if a block was clicked
|
||||
for(auto & blockIt : blocks)
|
||||
@ -818,7 +853,7 @@ void GraphView::mousePressEvent(QMouseEvent *event)
|
||||
}
|
||||
|
||||
// Check if a line beginning/end was clicked
|
||||
for(auto & blockIt : this->blocks)
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
for(GraphEdge & edge : block.edges)
|
||||
@ -850,25 +885,45 @@ void GraphView::mousePressEvent(QMouseEvent *event)
|
||||
if(event->button() == Qt::LeftButton)
|
||||
{
|
||||
//Left click outside any block, enter scrolling mode
|
||||
this->scroll_base_x = event->x();
|
||||
this->scroll_base_y = event->y();
|
||||
this->scroll_mode = true;
|
||||
this->setCursor(Qt::ClosedHandCursor);
|
||||
this->viewport()->grabMouse();
|
||||
scroll_base_x = event->x();
|
||||
scroll_base_y = event->y();
|
||||
scroll_mode = true;
|
||||
setCursor(Qt::ClosedHandCursor);
|
||||
viewport()->grabMouse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void GraphView::mouseMoveEvent(QMouseEvent* event)
|
||||
{
|
||||
if(this->scroll_mode)
|
||||
if(scroll_mode)
|
||||
{
|
||||
int x_delta = this->scroll_base_x - event->x();
|
||||
int y_delta = this->scroll_base_y - event->y();
|
||||
this->scroll_base_x = event->x();
|
||||
this->scroll_base_y = event->y();
|
||||
this->horizontalScrollBar()->setValue(this->horizontalScrollBar()->value() + x_delta);
|
||||
this->verticalScrollBar()->setValue(this->verticalScrollBar()->value() + y_delta);
|
||||
int x_delta = scroll_base_x - event->x();
|
||||
int y_delta = scroll_base_y - event->y();
|
||||
scroll_base_x = event->x();
|
||||
scroll_base_y = event->y();
|
||||
horizontalScrollBar()->setValue(horizontalScrollBar()->value() + x_delta);
|
||||
verticalScrollBar()->setValue(verticalScrollBar()->value() + y_delta);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::mouseDoubleClickEvent(QMouseEvent *event)
|
||||
{
|
||||
int x = ((event->pos().x() - unscrolled_render_offset_x) / current_scale) + horizontalScrollBar()->value();
|
||||
int y = ((event->pos().y() - unscrolled_render_offset_y) / current_scale) + verticalScrollBar()->value();
|
||||
|
||||
// Check if a block was clicked
|
||||
for(auto & blockIt : blocks)
|
||||
{
|
||||
GraphBlock &block = blockIt.second;
|
||||
|
||||
if((block.x <= x) && (block.y <= y) &&
|
||||
(x <= block.x + block.width) & (y <= block.y + block.height))
|
||||
{
|
||||
QPoint pos = QPoint(x - block.x, y - block.y);
|
||||
blockDoubleClicked(block, event, pos);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -883,10 +938,10 @@ void GraphView::mouseReleaseEvent(QMouseEvent* event)
|
||||
if(event->button() != Qt::LeftButton)
|
||||
return;
|
||||
|
||||
if(this->scroll_mode)
|
||||
if(scroll_mode)
|
||||
{
|
||||
this->scroll_mode = false;
|
||||
this->setCursor(Qt::ArrowCursor);
|
||||
this->viewport()->releaseMouse();
|
||||
scroll_mode = false;
|
||||
setCursor(Qt::ArrowCursor);
|
||||
viewport()->releaseMouse();
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include <QWidget>
|
||||
#include <QAbstractScrollArea>
|
||||
#include <QScrollBar>
|
||||
#include <QElapsedTimer>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
@ -19,8 +20,8 @@ class GraphView : public QAbstractScrollArea
|
||||
|
||||
enum class LayoutType
|
||||
{
|
||||
Wide,
|
||||
Medium,
|
||||
Wide,
|
||||
Narrow,
|
||||
};
|
||||
public:
|
||||
@ -101,10 +102,17 @@ protected:
|
||||
QColor backgroundColor = QColor(Qt::white);
|
||||
// The vertical margin between blocks
|
||||
int block_vertical_margin = 32;
|
||||
int block_horizontal_margin = 10;
|
||||
|
||||
// Padding inside the block
|
||||
int block_padding = 16;
|
||||
|
||||
// Zoom data
|
||||
double current_scale = 1.0;
|
||||
|
||||
int unscrolled_render_offset_x = 0;
|
||||
int unscrolled_render_offset_y = 0;
|
||||
|
||||
void addBlock(GraphView::GraphBlock block);
|
||||
void setEntry(ut64 e);
|
||||
void computeGraph(ut64 entry);
|
||||
@ -112,6 +120,7 @@ protected:
|
||||
// Callbacks that should be overridden
|
||||
virtual void drawBlock(QPainter & p, GraphView::GraphBlock &block);
|
||||
virtual void blockClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos);
|
||||
virtual void blockDoubleClicked(GraphView::GraphBlock &block, QMouseEvent *event, QPoint pos);
|
||||
virtual void blockTransitionedTo(GraphView::GraphBlock *to);
|
||||
virtual EdgeConfiguration edgeConfiguration(GraphView::GraphBlock &from, GraphView::GraphBlock *to);
|
||||
|
||||
@ -158,6 +167,7 @@ private slots:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QMouseEvent *event) override;
|
||||
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user