mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-18 18:38:51 +00:00
Refactor Refresh and Display of Overview (#1453)
This commit is contained in:
parent
34387c74b1
commit
7eb62a976c
@ -240,18 +240,23 @@ void MainWindow::initDocks()
|
||||
hexdumpDock = new HexdumpWidget(this, ui->actionHexdump);
|
||||
pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode);
|
||||
consoleDock = new ConsoleWidget(this, ui->actionConsole);
|
||||
|
||||
overviewDock = new OverviewWidget(this, ui->actionOverview);
|
||||
overviewDock->hide();
|
||||
graphDock = new GraphWidget(this, ui->actionGraph);
|
||||
connect(overviewDock, &OverviewWidget::isAvailableChanged, this, [this](bool isAvailable) {
|
||||
ui->actionOverview->setEnabled(isAvailable);
|
||||
});
|
||||
ui->actionOverview->setEnabled(overviewDock->getIsAvailable());
|
||||
connect(ui->actionOverview, &QAction::toggled, [this](bool checked) {
|
||||
if (checked) {
|
||||
overviewDock->setUserClosed(false);
|
||||
forceUpdateOverview();
|
||||
if (targetGraphDock) {
|
||||
toggleOverview(true, targetGraphDock);
|
||||
}
|
||||
overviewDock->show();
|
||||
} else {
|
||||
overviewDock->hide();
|
||||
}
|
||||
});
|
||||
|
||||
ui->actionOverview->setChecked(overviewDock->getUserOpened());
|
||||
graphDock = new GraphWidget(this, ui->actionGraph);
|
||||
sectionsDock = new SectionsWidget(this, ui->actionSections);
|
||||
segmentsDock = new SegmentsWidget(this, ui->actionSegments);
|
||||
entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints);
|
||||
@ -297,124 +302,9 @@ void MainWindow::toggleOverview(bool visibility, GraphWidget *targetGraph)
|
||||
if (!overviewDock) {
|
||||
return;
|
||||
}
|
||||
ui->actionOverview->setEnabled(visibility);
|
||||
if (overviewDock->getUserClosed() || !visibility) {
|
||||
return;
|
||||
if (visibility) {
|
||||
overviewDock->setTargetGraphWidget(targetGraph);
|
||||
}
|
||||
targetGraphDock = targetGraph;
|
||||
connect(targetGraphDock->getGraphView(), SIGNAL(refreshBlock()), this, SLOT(updateOverview()));
|
||||
connect(targetGraphDock->getGraphView(), SIGNAL(viewRefreshed()), this, SLOT(forceUpdateOverview()));
|
||||
connect(targetGraphDock->getGraphView(), SIGNAL(viewZoomed()), this, SLOT(updateOverview()));
|
||||
connect(targetGraphDock, &GraphWidget::graphClose, [this]() {
|
||||
disconnectOverview();
|
||||
enableOverviewMenu(false);
|
||||
overviewDock->hide();
|
||||
});
|
||||
connect(overviewDock->getGraphView(), SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
||||
connect(overviewDock->getGraphView(), SIGNAL(refreshBlock()), this, SLOT(updateOverviewAddr()));
|
||||
connect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::forceUpdateOverview);
|
||||
connect(overviewDock, &OverviewWidget::graphClose, [this]() {
|
||||
ui->actionOverview->setChecked(false);
|
||||
if (!core->isGraphEmpty()) {
|
||||
overviewDock->setUserClosed(true);
|
||||
}
|
||||
});
|
||||
connect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview())); // TODO: remove this, overviewDock handles resize itself!
|
||||
}
|
||||
|
||||
void MainWindow::disconnectOverview()
|
||||
{
|
||||
if (targetGraphDock) {
|
||||
disconnect(targetGraphDock->getGraphView(), SIGNAL(refreshBlock()), this, SLOT(updateOverview()));
|
||||
disconnect(targetGraphDock->getGraphView(), SIGNAL(viewRefreshed()), this, SLOT(updateOverview()));
|
||||
disconnect(targetGraphDock->getGraphView(), SIGNAL(viewZoomed()), this, SLOT(updateOverview()));
|
||||
}
|
||||
if (overviewDock) {
|
||||
disconnect(overviewDock->getGraphView(), SIGNAL(mouseMoved()), this, SLOT(adjustGraph()));
|
||||
disconnect(overviewDock->getGraphView(), SIGNAL(refreshBlock()), this, SLOT(updateOverviewAddr()));
|
||||
disconnect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::forceUpdateOverview);
|
||||
disconnect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview())); // TODO: remove this, overviewDock handles resize itself!
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::setOverviewData()
|
||||
{
|
||||
auto &mainGraphView = *targetGraphDock->getGraphView();
|
||||
overviewDock->getGraphView()->setData(mainGraphView.getWidth(), mainGraphView.getHeight(),
|
||||
mainGraphView.getBlocks(), mainGraphView.getEdgeConfigurations());
|
||||
}
|
||||
|
||||
bool MainWindow::isOverviewActive()
|
||||
{
|
||||
if (!overviewDock || overviewDock->getUserClosed()) {
|
||||
return false;
|
||||
}
|
||||
if (core->isGraphEmpty()) {
|
||||
enableOverviewMenu(false);
|
||||
overviewDock->hide();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void MainWindow::updateOverviewAddr()
|
||||
{
|
||||
overviewDock->getGraphView()->currentFcnAddr = targetGraphDock->getGraphView()->currentFcnAddr;
|
||||
}
|
||||
|
||||
void MainWindow::forceUpdateOverview()
|
||||
{
|
||||
if (!isOverviewActive()) {
|
||||
return;
|
||||
}
|
||||
setOverviewData();
|
||||
drawOverview();
|
||||
}
|
||||
|
||||
void MainWindow::updateOverview()
|
||||
{
|
||||
if (!isOverviewActive()) {
|
||||
return;
|
||||
}
|
||||
if (overviewDock->getGraphView()->currentFcnAddr != targetGraphDock->getGraphView()->currentFcnAddr) {
|
||||
setOverviewData();
|
||||
}
|
||||
drawOverview();
|
||||
}
|
||||
|
||||
void MainWindow::drawOverview()
|
||||
{
|
||||
qreal curScale = overviewDock->getGraphView()->current_scale;
|
||||
qreal baseScale = targetGraphDock->getGraphView()->current_scale;
|
||||
qreal w = targetGraphDock->getGraphView()->viewport()->width() * curScale / baseScale;
|
||||
qreal h = targetGraphDock->getGraphView()->viewport()->height() * curScale / baseScale;
|
||||
int graph_offset_x = targetGraphDock->getGraphView()->offset.x();
|
||||
int graph_offset_y = targetGraphDock->getGraphView()->offset.y();
|
||||
int overview_offset_x = overviewDock->getGraphView()->offset.x();
|
||||
int overview_offset_y = overviewDock->getGraphView()->offset.y();
|
||||
int rangeRectX = graph_offset_x * curScale - overview_offset_x * curScale;
|
||||
int rangeRectY = graph_offset_y * curScale - overview_offset_y * curScale;
|
||||
|
||||
overviewDock->getGraphView()->rangeRect = QRectF(rangeRectX, rangeRectY, w, h);
|
||||
overviewDock->getGraphView()->viewport()->update();
|
||||
enableOverviewMenu(true);
|
||||
overviewDock->show();
|
||||
}
|
||||
|
||||
void MainWindow::adjustGraph()
|
||||
{
|
||||
if (!overviewDock) {
|
||||
return;
|
||||
}
|
||||
|
||||
qreal curScale = overviewDock->getGraphView()->current_scale;
|
||||
int rectx = overviewDock->getGraphView()->rangeRect.x();
|
||||
int recty = overviewDock->getGraphView()->rangeRect.y();
|
||||
int overview_offset_x = overviewDock->getGraphView()->offset.x();
|
||||
int overview_offset_y = overviewDock->getGraphView()->offset.y();
|
||||
targetGraphDock->getGraphView()->offset.rx() = rectx /curScale + overview_offset_x;
|
||||
targetGraphDock->getGraphView()->offset.ry() = recty /curScale + overview_offset_y;
|
||||
targetGraphDock->getGraphView()->viewport()->update();
|
||||
}
|
||||
|
||||
void MainWindow::updateTasksIndicator()
|
||||
@ -931,12 +821,6 @@ void MainWindow::enableDebugWidgetsMenu(bool enable)
|
||||
ui->menuAddDebugWidgets->setEnabled(enable);
|
||||
}
|
||||
|
||||
void MainWindow::enableOverviewMenu(bool enable)
|
||||
{
|
||||
ui->actionOverview->setEnabled(enable);
|
||||
ui->actionOverview->setChecked(enable);
|
||||
}
|
||||
|
||||
void MainWindow::resetToDefaultLayout()
|
||||
{
|
||||
hideAllDocks();
|
||||
@ -1005,7 +889,6 @@ void MainWindow::on_actionFunctionsRename_triggered()
|
||||
|
||||
void MainWindow::on_actionDefault_triggered()
|
||||
{
|
||||
disconnectOverview();
|
||||
if (core->currentlyDebugging) {
|
||||
resetToDebugLayout();
|
||||
} else {
|
||||
|
@ -186,13 +186,6 @@ private slots:
|
||||
void changeDebugView();
|
||||
void changeDefinedView();
|
||||
|
||||
void disconnectOverview();
|
||||
void updateOverview();
|
||||
void forceUpdateOverview();
|
||||
void updateOverviewAddr();
|
||||
void drawOverview();
|
||||
void adjustGraph();
|
||||
|
||||
private:
|
||||
CutterCore *core;
|
||||
|
||||
@ -216,7 +209,6 @@ private:
|
||||
HexdumpWidget *hexdumpDock = nullptr;
|
||||
PseudocodeWidget *pseudocodeDock = nullptr;
|
||||
GraphWidget *graphDock = nullptr;
|
||||
GraphWidget *targetGraphDock = nullptr;
|
||||
OverviewWidget *overviewDock = nullptr;
|
||||
EntrypointWidget *entrypointDock = nullptr;
|
||||
FunctionsWidget *functionsDock = nullptr;
|
||||
@ -265,7 +257,6 @@ private:
|
||||
void showZenDocks();
|
||||
void showDebugDocks();
|
||||
void enableDebugWidgetsMenu(bool enable);
|
||||
void enableOverviewMenu(bool enable);
|
||||
|
||||
void toggleDockWidget(QDockWidget *dock_widget, bool show);
|
||||
|
||||
|
@ -190,7 +190,7 @@ void DisassemblerGraphView::loadCurrentGraph()
|
||||
highlight_token = nullptr;
|
||||
}
|
||||
|
||||
bool emptyGraph = functions.isEmpty();
|
||||
emptyGraph = functions.isEmpty();
|
||||
if (emptyGraph) {
|
||||
// If there's no function to print, just add a message
|
||||
if (!emptyText) {
|
||||
@ -375,8 +375,8 @@ void DisassemblerGraphView::initFont()
|
||||
|
||||
void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
{
|
||||
int blockX = block.x - offset.x();
|
||||
int blockY = block.y - offset.y();
|
||||
int blockX = block.x - getViewOffset().x();
|
||||
int blockY = block.y - getViewOffset().y();
|
||||
|
||||
p.setPen(Qt::black);
|
||||
p.setBrush(Qt::gray);
|
||||
@ -517,7 +517,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
qreal lineHeightRender = charHeight;
|
||||
for (auto &line : db.header_text.lines) {
|
||||
qreal lineYRender = y;
|
||||
lineYRender *= current_scale;
|
||||
lineYRender *= getViewScale();
|
||||
// Check if line does NOT intersects with view area
|
||||
if (0 > lineYRender + lineHeightRender
|
||||
|| render_height < lineYRender) {
|
||||
@ -543,7 +543,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
}
|
||||
for (auto &line : instr.text.lines) {
|
||||
qreal lineYRender = y;
|
||||
lineYRender *= current_scale;
|
||||
lineYRender *= getViewScale();
|
||||
if (0 > lineYRender + lineHeightRender
|
||||
|| render_height < lineYRender) {
|
||||
y += charHeight;
|
||||
@ -705,16 +705,17 @@ void DisassemblerGraphView::zoom(QPointF mouseRelativePos, double velocity)
|
||||
{
|
||||
mouseRelativePos.rx() *= size().width();
|
||||
mouseRelativePos.ry() *= size().height();
|
||||
mouseRelativePos /= current_scale;
|
||||
mouseRelativePos /= getViewScale();
|
||||
|
||||
auto globalMouse = mouseRelativePos + offset;
|
||||
mouseRelativePos *= current_scale;
|
||||
current_scale *= std::pow(1.25, velocity);
|
||||
current_scale = std::max(current_scale, 0.3);
|
||||
mouseRelativePos /= current_scale;
|
||||
auto globalMouse = mouseRelativePos + getViewOffset();
|
||||
mouseRelativePos *= getViewScale();
|
||||
qreal newScale = getViewScale() * std::pow(1.25, velocity);
|
||||
newScale = std::max(newScale, 0.3);
|
||||
mouseRelativePos /= newScale;
|
||||
setViewScale(newScale);
|
||||
|
||||
// Adjusting offset, so that zooming will be approaching to the cursor.
|
||||
offset = globalMouse.toPoint() - mouseRelativePos.toPoint();
|
||||
setViewOffset(globalMouse.toPoint() - mouseRelativePos.toPoint());
|
||||
|
||||
viewport()->update();
|
||||
emit viewZoomed();
|
||||
@ -722,7 +723,7 @@ void DisassemblerGraphView::zoom(QPointF mouseRelativePos, double velocity)
|
||||
|
||||
void DisassemblerGraphView::zoomReset()
|
||||
{
|
||||
current_scale = 1.0;
|
||||
setViewScale(1.0);
|
||||
viewport()->update();
|
||||
emit viewZoomed();
|
||||
}
|
||||
@ -992,6 +993,12 @@ void DisassemblerGraphView::wheelEvent(QWheelEvent *event)
|
||||
emit graphMoved();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
GraphView::resizeEvent(event);
|
||||
emit resized();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
// DisassemblerGraphView is always dirty
|
||||
|
@ -129,6 +129,7 @@ protected:
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void mouseMoveEvent(QMouseEvent *event) override;
|
||||
void wheelEvent(QWheelEvent *event) override;
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
@ -196,6 +197,10 @@ signals:
|
||||
void viewRefreshed();
|
||||
void viewZoomed();
|
||||
void graphMoved();
|
||||
void resized();
|
||||
|
||||
public:
|
||||
bool isGraphEmpty() { return emptyGraph; }
|
||||
};
|
||||
|
||||
#endif // DISASSEMBLERGRAPHVIEW_H
|
||||
|
@ -143,6 +143,18 @@ void GraphView::beginMouseDrag(QMouseEvent *event)
|
||||
viewport()->grabMouse();
|
||||
}
|
||||
|
||||
void GraphView::setViewOffset(QPoint offset)
|
||||
{
|
||||
this->offset = offset;
|
||||
emit viewOffsetChanged(offset);
|
||||
}
|
||||
|
||||
void GraphView::setViewScale(qreal scale)
|
||||
{
|
||||
this->current_scale = scale;
|
||||
emit viewScaleChanged(scale);
|
||||
}
|
||||
|
||||
QSize GraphView::getCacheSize()
|
||||
{
|
||||
return
|
||||
@ -214,10 +226,6 @@ void GraphView::paintEvent(QPaintEvent *)
|
||||
QPainter p(viewport());
|
||||
p.drawPixmap(target, pixmap, source);
|
||||
}
|
||||
|
||||
if(cacheWasDirty) { // TODO: does this condition make sense?
|
||||
emit refreshBlock();
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::paintGraphCache()
|
||||
@ -341,20 +349,27 @@ void GraphView::paintGraphCache()
|
||||
|
||||
void GraphView::center()
|
||||
{
|
||||
centerX();
|
||||
centerY();
|
||||
centerX(false);
|
||||
centerY(false);
|
||||
emit viewOffsetChanged(offset);
|
||||
}
|
||||
|
||||
void GraphView::centerX()
|
||||
void GraphView::centerX(bool emitSignal)
|
||||
{
|
||||
offset.rx() = -((viewport()->width() - width * current_scale) / 2);
|
||||
offset.rx() /= current_scale;
|
||||
if (emitSignal) {
|
||||
emit viewOffsetChanged(offset);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::centerY()
|
||||
void GraphView::centerY(bool emitSignal)
|
||||
{
|
||||
offset.ry() = -((viewport()->height() - height * current_scale) / 2);
|
||||
offset.ry() /= current_scale;
|
||||
if (emitSignal) {
|
||||
emit viewOffsetChanged(offset);
|
||||
}
|
||||
}
|
||||
|
||||
void GraphView::showBlock(GraphBlock &block)
|
||||
@ -365,16 +380,17 @@ void GraphView::showBlock(GraphBlock &block)
|
||||
void GraphView::showBlock(GraphBlock *block)
|
||||
{
|
||||
if (width * current_scale <= viewport()->width()) {
|
||||
centerX();
|
||||
centerX(false);
|
||||
} else {
|
||||
int render_width = viewport()->width() / current_scale;
|
||||
offset.rx() = block->x - ((render_width - block->width) / 2);
|
||||
}
|
||||
if (height * current_scale <= viewport()->height()) {
|
||||
centerY();
|
||||
centerY(false);
|
||||
} else {
|
||||
offset.ry() = block->y - 30;
|
||||
}
|
||||
emit viewOffsetChanged(offset);
|
||||
blockTransitionedTo(block);
|
||||
viewport()->update();
|
||||
}
|
||||
@ -463,6 +479,7 @@ void GraphView::mouseMoveEvent(QMouseEvent *event)
|
||||
if (scroll_mode) {
|
||||
offset.rx() += (scroll_base_x - event->x()) / current_scale;
|
||||
offset.ry() += (scroll_base_y - event->y()) / current_scale;
|
||||
emit viewOffsetChanged(offset);
|
||||
scroll_base_x = event->x();
|
||||
scroll_base_y = event->y();
|
||||
viewport()->update();
|
||||
@ -510,6 +527,7 @@ void GraphView::keyPressEvent(QKeyEvent* event)
|
||||
}
|
||||
offset.rx() += dx;
|
||||
offset.ry() += dy;
|
||||
emit viewOffsetChanged(offset);
|
||||
viewport()->update();
|
||||
event->accept();
|
||||
}
|
||||
@ -540,6 +558,7 @@ void GraphView::wheelEvent(QWheelEvent *event)
|
||||
|
||||
delta /= current_scale;
|
||||
offset += delta;
|
||||
emit viewOffsetChanged(offset);
|
||||
|
||||
viewport()->update();
|
||||
event->accept();
|
||||
|
@ -24,8 +24,10 @@ class QOpenGLWidget;
|
||||
class GraphView : public QAbstractScrollArea
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void refreshBlock();
|
||||
void viewOffsetChanged(QPoint offset);
|
||||
void viewScaleChanged(qreal scale);
|
||||
|
||||
public:
|
||||
using GraphBlock = GraphLayout::GraphBlock;
|
||||
@ -44,17 +46,12 @@ public:
|
||||
void showBlock(GraphBlock &block);
|
||||
void showBlock(GraphBlock *block);
|
||||
|
||||
// Zoom data
|
||||
qreal current_scale = 1.0;
|
||||
|
||||
QPoint offset = QPoint(0, 0);
|
||||
|
||||
/**
|
||||
* @brief keep the current addr of the fcn of Graph
|
||||
* Everytime overview updates its contents, it compares this value with the one in Graph
|
||||
* if they aren't same, then Overview needs to update the pixmap cache.
|
||||
*/
|
||||
ut64 currentFcnAddr = 0; // TODO: move application specific code out of graph view
|
||||
ut64 currentFcnAddr = RVA_INVALID; // TODO: move application specific code out of graph view
|
||||
|
||||
protected:
|
||||
std::unordered_map<ut64, GraphBlock> blocks;
|
||||
@ -91,17 +88,22 @@ protected:
|
||||
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
|
||||
void center();
|
||||
void centerX();
|
||||
void centerY();
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
|
||||
private:
|
||||
void centerX(bool emitSignal);
|
||||
void centerY(bool emitSignal);
|
||||
|
||||
void paintGraphCache();
|
||||
|
||||
bool checkPointClicked(QPointF &point, int x, int y, bool above_y = false);
|
||||
|
||||
// Zoom data
|
||||
qreal current_scale = 1.0;
|
||||
|
||||
QPoint offset = QPoint(0, 0);
|
||||
|
||||
ut64 entry;
|
||||
|
||||
std::unique_ptr<GraphLayout> graphLayoutSystem;
|
||||
@ -141,6 +143,16 @@ private:
|
||||
|
||||
QPolygonF recalculatePolygon(QPolygonF polygon);
|
||||
void beginMouseDrag(QMouseEvent *event);
|
||||
|
||||
public:
|
||||
QPoint getViewOffset() const { return offset; }
|
||||
void setViewOffset(QPoint offset);
|
||||
qreal getViewScale() const { return current_scale; }
|
||||
void setViewScale(qreal scale);
|
||||
|
||||
void center();
|
||||
void centerX() { centerX(true); }
|
||||
void centerY() { centerY(true); }
|
||||
};
|
||||
|
||||
#endif // GRAPHVIEW_H
|
||||
|
@ -51,7 +51,7 @@ QWidget *GraphWidget::widgetToFocusOnRaise()
|
||||
void GraphWidget::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
CutterDockWidget::closeEvent(event);
|
||||
emit graphClose();
|
||||
emit graphClosed();
|
||||
}
|
||||
|
||||
DisassemblerGraphView *GraphWidget::getGraphView() const
|
||||
|
@ -17,7 +17,7 @@ public:
|
||||
DisassemblerGraphView *getGraphView() const;
|
||||
|
||||
signals:
|
||||
void graphClose();
|
||||
void graphClosed();
|
||||
|
||||
protected:
|
||||
QWidget *widgetToFocusOnRaise() override;
|
||||
|
@ -24,6 +24,7 @@ void OverviewView::setData(int baseWidth, int baseHeight,
|
||||
edgeConfigurations = baseEdgeConfigurations;
|
||||
scaleAndCenter();
|
||||
setCacheDirty();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
OverviewView::~OverviewView()
|
||||
@ -32,11 +33,9 @@ OverviewView::~OverviewView()
|
||||
|
||||
void OverviewView::scaleAndCenter()
|
||||
{
|
||||
current_scale = (qreal)viewport()->width() / width;
|
||||
qreal h_scale = (qreal)viewport()->height() / height;
|
||||
if (current_scale > h_scale) {
|
||||
current_scale = h_scale;
|
||||
}
|
||||
qreal wScale = (qreal)viewport()->width() / width;
|
||||
qreal hScale = (qreal)viewport()->height() / height;
|
||||
setViewScale(std::min(wScale, hScale));
|
||||
center();
|
||||
}
|
||||
|
||||
@ -48,8 +47,8 @@ void OverviewView::refreshView()
|
||||
|
||||
void OverviewView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
|
||||
{
|
||||
int blockX = block.x - offset.x();
|
||||
int blockY = block.y - offset.y();
|
||||
int blockX = block.x - getViewOffset().x();
|
||||
int blockY = block.y - getViewOffset().y();
|
||||
|
||||
p.setPen(Qt::black);
|
||||
p.setBrush(Qt::gray);
|
||||
@ -138,7 +137,7 @@ GraphView::EdgeConfiguration OverviewView::edgeConfiguration(GraphView::GraphBlo
|
||||
auto baseEcIt = edgeConfigurations.find({from.entry, to->entry});
|
||||
if (baseEcIt != edgeConfigurations.end())
|
||||
ec = baseEcIt->second;
|
||||
ec.width_scale = current_scale;
|
||||
ec.width_scale = getViewScale();
|
||||
return ec;
|
||||
}
|
||||
|
||||
@ -149,3 +148,9 @@ void OverviewView::colorsUpdatedSlot()
|
||||
backgroundColor = ConfigColor("gui.background");
|
||||
refreshView();
|
||||
}
|
||||
|
||||
void OverviewView::setRangeRect(QRectF rect)
|
||||
{
|
||||
rangeRect = rect;
|
||||
viewport()->update();
|
||||
}
|
||||
|
@ -22,11 +22,6 @@ public:
|
||||
OverviewView(QWidget *parent);
|
||||
~OverviewView() override;
|
||||
|
||||
/**
|
||||
* @brief a rect on Overview to show where you are on Graph
|
||||
*/
|
||||
QRectF rangeRect;
|
||||
|
||||
/**
|
||||
* @brief Graph access this function to set minimum set of the data
|
||||
* @param baseWidth width of Graph when it computed the blocks
|
||||
@ -87,6 +82,11 @@ private:
|
||||
*/
|
||||
QPointF initialDiff;
|
||||
|
||||
/**
|
||||
* @brief a rect on Overview to show where you are on Graph
|
||||
*/
|
||||
QRectF rangeRect;
|
||||
|
||||
/**
|
||||
* @brief calculate the scale to fit the all nodes in and center them in the viewport
|
||||
*/
|
||||
@ -124,6 +124,10 @@ private:
|
||||
* @brief edgeConfigurations edge styles computed by DisassemblerGraphView
|
||||
*/
|
||||
DisassemblerGraphView::EdgeConfigurationMapping edgeConfigurations;
|
||||
|
||||
public:
|
||||
QRectF getRangeRect() { return rangeRect; }
|
||||
void setRangeRect(QRectF rect);
|
||||
};
|
||||
|
||||
#endif // OVERVIEWVIEW_H
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include "core/MainWindow.h"
|
||||
#include "OverviewWidget.h"
|
||||
#include "GraphWidget.h"
|
||||
#include "OverviewView.h"
|
||||
|
||||
OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) :
|
||||
@ -10,14 +11,12 @@ OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) :
|
||||
setAllowedAreas(Qt::AllDockWidgetAreas);
|
||||
graphView = new OverviewView(this);
|
||||
setWidget(graphView);
|
||||
refreshDeferrer = createRefreshDeferrer([this]() {
|
||||
updateContents();
|
||||
});
|
||||
targetGraphWidget = nullptr;
|
||||
|
||||
connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) {
|
||||
if (visibility) {
|
||||
updateContents();
|
||||
}
|
||||
connect(graphView, SIGNAL(mouseMoved()), this, SLOT(updateTargetView()));
|
||||
|
||||
graphDataRefreshDeferrer = createRefreshDeferrer([this]() {
|
||||
updateGraphData();
|
||||
});
|
||||
}
|
||||
|
||||
@ -26,35 +25,124 @@ OverviewWidget::~OverviewWidget() {}
|
||||
void OverviewWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
graphView->refreshView();
|
||||
updateRangeRect();
|
||||
QDockWidget::resizeEvent(event);
|
||||
emit resized();
|
||||
}
|
||||
|
||||
void OverviewWidget::updateContents()
|
||||
void OverviewWidget::showEvent(QShowEvent *event)
|
||||
{
|
||||
if (!refreshDeferrer->attemptRefresh(nullptr)) {
|
||||
return;
|
||||
}
|
||||
graphView->refreshView();
|
||||
CutterDockWidget::showEvent(event);
|
||||
setUserOpened(true);
|
||||
}
|
||||
|
||||
void OverviewWidget::closeEvent(QCloseEvent *event)
|
||||
{
|
||||
CutterDockWidget::closeEvent(event);
|
||||
emit graphClose();
|
||||
setUserOpened(false);
|
||||
}
|
||||
|
||||
void OverviewWidget::setUserClosed(bool value)
|
||||
void OverviewWidget::setIsAvailable(bool isAvailable)
|
||||
{
|
||||
userClosed = value;
|
||||
if (this->isAvailable == isAvailable) {
|
||||
return;
|
||||
}
|
||||
this->isAvailable = isAvailable;
|
||||
if(!isAvailable) {
|
||||
hide();
|
||||
} else if(userOpened) {
|
||||
show();
|
||||
}
|
||||
emit isAvailableChanged(isAvailable);
|
||||
}
|
||||
|
||||
bool OverviewWidget::getUserClosed() const
|
||||
void OverviewWidget::setUserOpened(bool userOpened)
|
||||
{
|
||||
return userClosed;
|
||||
if (this->userOpened == userOpened) {
|
||||
return;
|
||||
}
|
||||
this->userOpened = userOpened;
|
||||
emit userOpenedChanged(userOpened);
|
||||
}
|
||||
|
||||
OverviewView *OverviewWidget::getGraphView() const
|
||||
void OverviewWidget::setTargetGraphWidget(GraphWidget *widget)
|
||||
{
|
||||
return graphView;
|
||||
if (widget == targetGraphWidget) {
|
||||
return;
|
||||
}
|
||||
if (targetGraphWidget) {
|
||||
disconnect(targetGraphWidget->getGraphView(), &DisassemblerGraphView::viewRefreshed, this, &OverviewWidget::updateGraphData);
|
||||
disconnect(targetGraphWidget->getGraphView(), &DisassemblerGraphView::resized, this, &OverviewWidget::updateRangeRect);
|
||||
disconnect(targetGraphWidget->getGraphView(), &GraphView::viewOffsetChanged, this, &OverviewWidget::updateRangeRect);
|
||||
disconnect(targetGraphWidget->getGraphView(), &GraphView::viewScaleChanged, this, &OverviewWidget::updateRangeRect);
|
||||
disconnect(targetGraphWidget, &GraphWidget::graphClosed, this, &OverviewWidget::targetClosed);
|
||||
}
|
||||
targetGraphWidget = widget;
|
||||
if (targetGraphWidget) {
|
||||
connect(targetGraphWidget->getGraphView(), &DisassemblerGraphView::viewRefreshed, this, &OverviewWidget::updateGraphData);
|
||||
connect(targetGraphWidget->getGraphView(), &DisassemblerGraphView::resized, this, &OverviewWidget::updateRangeRect);
|
||||
connect(targetGraphWidget->getGraphView(), &GraphView::viewOffsetChanged, this, &OverviewWidget::updateRangeRect);
|
||||
connect(targetGraphWidget->getGraphView(), &GraphView::viewScaleChanged, this, &OverviewWidget::updateRangeRect);
|
||||
connect(targetGraphWidget, &GraphWidget::graphClosed, this, &OverviewWidget::targetClosed);
|
||||
}
|
||||
updateGraphData();
|
||||
updateRangeRect();
|
||||
setIsAvailable(targetGraphWidget != nullptr);
|
||||
}
|
||||
|
||||
void OverviewWidget::targetClosed()
|
||||
{
|
||||
setTargetGraphWidget(nullptr);
|
||||
}
|
||||
|
||||
void OverviewWidget::updateTargetView()
|
||||
{
|
||||
qreal curScale = graphView->getViewScale();
|
||||
int rectx = graphView->getRangeRect().x();
|
||||
int recty = graphView->getRangeRect().y();
|
||||
int overview_offset_x = graphView->getViewOffset().x();
|
||||
int overview_offset_y = graphView->getViewOffset().y();
|
||||
QPoint newOffset;
|
||||
newOffset.rx() = rectx / curScale + overview_offset_x;
|
||||
newOffset.ry() = recty / curScale + overview_offset_y;
|
||||
targetGraphWidget->getGraphView()->setViewOffset(newOffset);
|
||||
targetGraphWidget->getGraphView()->viewport()->update();
|
||||
}
|
||||
|
||||
void OverviewWidget::updateGraphData()
|
||||
{
|
||||
if (!graphDataRefreshDeferrer->attemptRefresh(nullptr)) {
|
||||
return;
|
||||
}
|
||||
if (targetGraphWidget && !targetGraphWidget->getGraphView()->isGraphEmpty()) {
|
||||
if (targetGraphWidget->getGraphView()->currentFcnAddr == graphView->currentFcnAddr) {
|
||||
return;
|
||||
}
|
||||
graphView->currentFcnAddr = targetGraphWidget->getGraphView()->currentFcnAddr;
|
||||
auto &mainGraphView = *targetGraphWidget->getGraphView();
|
||||
graphView->setData(mainGraphView.getWidth(), mainGraphView.getHeight(),
|
||||
mainGraphView.getBlocks(), mainGraphView.getEdgeConfigurations());
|
||||
} else {
|
||||
graphView->currentFcnAddr = RVA_INVALID;
|
||||
graphView->setData(0, 0, {}, {});
|
||||
graphView->setRangeRect(QRectF(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
||||
void OverviewWidget::updateRangeRect() {
|
||||
if (targetGraphWidget) {
|
||||
qreal curScale = graphView->getViewScale();
|
||||
qreal baseScale = targetGraphWidget->getGraphView()->getViewScale();
|
||||
qreal w = targetGraphWidget->getGraphView()->viewport()->width() * curScale / baseScale;
|
||||
qreal h = targetGraphWidget->getGraphView()->viewport()->height() * curScale / baseScale;
|
||||
int graph_offset_x = targetGraphWidget->getGraphView()->getViewOffset().x();
|
||||
int graph_offset_y = targetGraphWidget->getGraphView()->getViewOffset().y();
|
||||
int overview_offset_x = graphView->getViewOffset().x();
|
||||
int overview_offset_y = graphView->getViewOffset().y();
|
||||
int rangeRectX = graph_offset_x * curScale - overview_offset_x * curScale;
|
||||
int rangeRectY = graph_offset_y * curScale - overview_offset_y * curScale;
|
||||
graphView->setRangeRect(QRectF(rangeRectX, rangeRectY, w, h));
|
||||
} else {
|
||||
graphView->setRangeRect(QRectF(0, 0, 0, 0));
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
|
||||
class MainWindow;
|
||||
class OverviewView;
|
||||
class GraphWidget;
|
||||
|
||||
class OverviewWidget : public CutterDockWidget
|
||||
{
|
||||
@ -14,45 +15,78 @@ public:
|
||||
explicit OverviewWidget(MainWindow *main, QAction *action = nullptr);
|
||||
~OverviewWidget();
|
||||
|
||||
OverviewView *getGraphView() const;
|
||||
|
||||
/*
|
||||
* @brief if user closed this widget explicitly
|
||||
*/
|
||||
bool getUserClosed() const;
|
||||
void setUserClosed(bool value);
|
||||
|
||||
private:
|
||||
RefreshDeferrer *refreshDeferrer;
|
||||
OverviewView *graphView;
|
||||
bool isAvailable = false;
|
||||
bool userOpened = false;
|
||||
|
||||
GraphWidget *targetGraphWidget;
|
||||
|
||||
RefreshDeferrer *graphDataRefreshDeferrer;
|
||||
|
||||
/**
|
||||
* @brief this takes care of scaling the overview when the widget is resized
|
||||
*/
|
||||
void resizeEvent(QResizeEvent *event) override;
|
||||
|
||||
void setIsAvailable(bool isAvailable);
|
||||
void setUserOpened(bool userOpened);
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief update the overview
|
||||
*/
|
||||
void updateContents();
|
||||
/*
|
||||
* @brief override closeEvent to emit graphClose
|
||||
*/
|
||||
void showEvent(QShowEvent *event) override;
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
|
||||
/**
|
||||
* @brief update the view in the target widget when the range rect in the overview is moved
|
||||
*/
|
||||
void updateTargetView();
|
||||
|
||||
/**
|
||||
* @brief update the content of the graph (blocks, edges) in the contained graphView from the target widget
|
||||
*/
|
||||
void updateGraphData();
|
||||
|
||||
/**
|
||||
* @brief update the rect to show the current view in the target widget
|
||||
*/
|
||||
void updateRangeRect();
|
||||
|
||||
void targetClosed();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief emit signal to update the rect
|
||||
*/
|
||||
void resized();
|
||||
/*
|
||||
* @brief emit signal to notify when this widget is closed
|
||||
|
||||
/**
|
||||
* @sa getIsAvailable()
|
||||
*/
|
||||
void graphClose();
|
||||
void isAvailableChanged(bool isAvailable);
|
||||
|
||||
private:
|
||||
OverviewView *graphView;
|
||||
bool userClosed = false;
|
||||
/**
|
||||
* @sa getUserOpened()
|
||||
*/
|
||||
void userOpenedChanged(bool userOpened);
|
||||
|
||||
public:
|
||||
GraphWidget *getTargetGraphWidget() { return targetGraphWidget; }
|
||||
void setTargetGraphWidget(GraphWidget *widget);
|
||||
|
||||
/**
|
||||
* @brief whether this widget makes sense to be show, i.e. the menu entry should be enabled
|
||||
*/
|
||||
bool getIsAvailable() const { return isAvailable; }
|
||||
|
||||
/**
|
||||
* @brief whether this widget is desired to be shown in general
|
||||
*
|
||||
* Will be false when the user closed the overview explicitly.
|
||||
* Also corresponds to the checked state of the menu entry for this widget.
|
||||
*/
|
||||
bool getUserOpened() const { return userOpened; }
|
||||
|
||||
OverviewView *getGraphView() const { return graphView; }
|
||||
};
|
||||
|
||||
#endif // OverviewWIDGET_H
|
||||
|
Loading…
Reference in New Issue
Block a user