diff --git a/src/core/MainWindow.cpp b/src/core/MainWindow.cpp index 87392130..e09a0fc4 100644 --- a/src/core/MainWindow.cpp +++ b/src/core/MainWindow.cpp @@ -200,7 +200,10 @@ void MainWindow::initUI() connect(ui->actionOverview, &QAction::toggled, [this](bool checked) { if (checked) { overviewDock->userClosed = false; - adjustOverview(); + forceUpdateOverview(); + if (targetGraphDock) { + toggleOverview(true, targetGraphDock); + } } }); sectionsDock = new SectionsWidget(this, ui->actionSections); @@ -298,34 +301,35 @@ void MainWindow::toggleOverview(bool visibility, GraphWidget *targetGraph) return; } targetGraphDock = targetGraph; - connect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview())); - connect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(adjustOverview())); - connect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(adjustOverview())); + connect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverview())); + connect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(updateOverview())); + connect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(updateOverview())); connect(targetGraphDock, &GraphWidget::graphClose, [this]() { disconnectOverview(); enableOverviewMenu(false); overviewDock->hide(); }); connect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph())); - connect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::adjustOverview); + connect(overviewDock->graphView, 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->userClosed = true; } }); - connect(overviewDock, SIGNAL(resized()), this, SLOT(adjustOverview())); + connect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview())); } void MainWindow::disconnectOverview() { - disconnect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview())); - disconnect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(adjustOverview())); - disconnect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(adjustOverview())); + disconnect(targetGraphDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverview())); + disconnect(targetGraphDock->graphView, SIGNAL(viewRefreshed()), this, SLOT(updateOverview())); + disconnect(targetGraphDock->graphView, SIGNAL(viewZoomed()), this, SLOT(updateOverview())); disconnect(overviewDock->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph())); - disconnect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::adjustOverview); - disconnect(overviewDock, SIGNAL(resized()), this, SLOT(adjustOverview())); - disconnect(overviewDock, &QDockWidget::visibilityChanged, this, nullptr); + disconnect(overviewDock->graphView, SIGNAL(refreshBlock()), this, SLOT(updateOverviewAddr())); + disconnect(overviewDock, &QDockWidget::dockLocationChanged, this, &MainWindow::forceUpdateOverview); + disconnect(overviewDock, SIGNAL(resized()), this, SLOT(forceUpdateOverview())); } void MainWindow::setOverviewData() @@ -334,17 +338,50 @@ void MainWindow::setOverviewData() targetGraphDock->graphView->getHeight(), targetGraphDock->graphView->getBlocks()); } -void MainWindow::adjustOverview() +bool MainWindow::isOverviewActive() { if (!overviewDock || overviewDock->userClosed) { - return; + return false; } if (core->isGraphEmpty()) { enableOverviewMenu(false); overviewDock->hide(); + return false; + } + return true; +} + +void MainWindow::updateOverviewAddr() +{ + overviewDock->graphView->currentFcnAddr = targetGraphDock->graphView->currentFcnAddr; +} + +void MainWindow::forceUpdateOverview() +{ + if (!isOverviewActive()) { return; } + overviewDock->graphView->useCache = false; setOverviewData(); + drawOverview(); +} + +void MainWindow::updateOverview() +{ + if (!isOverviewActive()) { + return; + } + if (overviewDock->graphView->currentFcnAddr != targetGraphDock->graphView->currentFcnAddr) { + overviewDock->graphView->useCache = false; + setOverviewData(); + } else { + overviewDock->graphView->useCache = true; + } + drawOverview(); +} + +void MainWindow::drawOverview() +{ qreal curScale = overviewDock->graphView->current_scale; qreal baseScale = targetGraphDock->graphView->current_scale; qreal w = targetGraphDock->graphView->viewport()->width() * curScale / baseScale; diff --git a/src/core/MainWindow.h b/src/core/MainWindow.h index eb4804ab..67c80f2d 100644 --- a/src/core/MainWindow.h +++ b/src/core/MainWindow.h @@ -137,10 +137,6 @@ public slots: void openNewFileFailed(); void toggleOverview(bool visibility, GraphWidget *targetGraph); - void disconnectOverview(); - void adjustOverview(); - void adjustGraph(); - private slots: void on_actionAbout_triggered(); void on_actionIssue_triggered(); @@ -193,6 +189,13 @@ private slots: void changeDebugView(); void changeDefinedView(); + void disconnectOverview(); + void updateOverview(); + void forceUpdateOverview(); + void updateOverviewAddr(); + void drawOverview(); + void adjustGraph(); + private: CutterCore *core; @@ -271,6 +274,7 @@ private: void updateDockActionsChecked(); void setOverviewData(); + bool isOverviewActive(); }; #endif // MAINWINDOW_H diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index d6ac3327..3f7a821f 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -182,6 +182,7 @@ void DisassemblerGraphView::loadCurrentGraph() QJsonArray functions; RAnalFunction *fcn = Core()->functionAt(seekable->getOffset()); if (fcn) { + currentFcnAddr = fcn->addr; QJsonDocument functionsDoc = Core()->cmdj("agJ " + RAddressString(fcn->addr)); functions = functionsDoc.array(); } @@ -211,14 +212,8 @@ void DisassemblerGraphView::loadCurrentGraph() // Refresh global "empty graph" variable so other widget know there is nothing to show here Core()->setGraphEmpty(emptyGraph); - Analysis anal; - anal.ready = true; - QJsonValue funcRef = functions.first(); QJsonObject func = funcRef.toObject(); - Function f; - f.ready = true; - f.entry = func["offset"].toVariant().toULongLong(); windowTitle = tr("Graph"); QString funcName = func["name"].toString().trimmed(); @@ -312,15 +307,10 @@ void DisassemblerGraphView::loadCurrentGraph() } disassembly_blocks[db.entry] = db; prepareGraphNode(gb); - f.blocks.push_back(db); addBlock(gb); } - anal.functions[f.entry] = f; - anal.status = "Ready."; - anal.entry = f.entry; - if (!func["blocks"].toArray().isEmpty()) { computeGraph(entry); } diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index e06fb1c8..c3783e16 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -83,32 +83,6 @@ class DisassemblerGraphView : public GraphView bool indirectcall = false; }; - struct Function { - bool ready; - ut64 entry; - ut64 update_id; - std::vector blocks; - }; - - struct Analysis { - ut64 entry = 0; - std::unordered_map functions; - bool ready = false; - ut64 update_id = 0; - QString status = "Analyzing..."; - - bool find_instr(ut64 addr, ut64 &func, ut64 &instr) - { - //TODO implement - Q_UNUSED(addr); - Q_UNUSED(func); - Q_UNUSED(instr); - return false; - } - - //dummy class - }; - public: DisassemblerGraphView(QWidget *parent); ~DisassemblerGraphView() override; @@ -129,7 +103,6 @@ public: int getWidth() { return width; } int getHeight() { return height; } - std::unordered_map getBlocks() { return blocks; } public slots: void refreshView(); diff --git a/src/widgets/GraphView.cpp b/src/widgets/GraphView.cpp index 536da0f4..c43edd31 100644 --- a/src/widgets/GraphView.cpp +++ b/src/widgets/GraphView.cpp @@ -381,7 +381,12 @@ QPolygonF GraphView::recalculatePolygon(QPolygonF polygon) void GraphView::paintEvent(QPaintEvent *event) { Q_UNUSED(event); - QPainter p(viewport()); + if (useCache) { + drawGraph(); + return; + } + pixmap = QPixmap(viewport()->width(), viewport()->height()); + QPainter p(&pixmap); p.setRenderHint(QPainter::Antialiasing); @@ -436,10 +441,18 @@ void GraphView::paintEvent(QPaintEvent *event) } } } - + drawGraph(); emit refreshBlock(); } +void GraphView::drawGraph() +{ + QRectF target(0.0, 0.0, viewport()->width(), viewport()->height()); + QRectF source(0.0, 0.0, viewport()->width(), viewport()->height()); + QPainter p(viewport()); + p.drawPixmap(target, pixmap, source); +} + // Prepare graph // This computes the position and (row/col based) size of the block // Recursively calls itself for each child of the GraphBlock diff --git a/src/widgets/GraphView.h b/src/widgets/GraphView.h index 123ffc10..ba81188c 100644 --- a/src/widgets/GraphView.h +++ b/src/widgets/GraphView.h @@ -104,6 +104,18 @@ public: int offset_x = 0; int offset_y = 0; + /** + * @brief flag to control if the cached pixmap should be used + */ + bool useCache = false; + + /** + * @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; + protected: std::unordered_map blocks; QColor backgroundColor = QColor(Qt::white); @@ -129,6 +141,7 @@ protected: virtual void wheelEvent(QWheelEvent *event) override; virtual EdgeConfiguration edgeConfiguration(GraphView::GraphBlock &from, GraphView::GraphBlock *to); + void drawGraph(); bool event(QEvent *event) override; // Mouse events @@ -142,6 +155,12 @@ protected: void centerY(); int width = 0; int height = 0; + + /** + * @brief pixmap that caches the graph nodes + */ + QPixmap pixmap; + private: bool checkPointClicked(QPointF &point, int x, int y, bool above_y = false); diff --git a/src/widgets/OverviewView.cpp b/src/widgets/OverviewView.cpp index 990685ea..b9f1fe75 100644 --- a/src/widgets/OverviewView.cpp +++ b/src/widgets/OverviewView.cpp @@ -19,14 +19,14 @@ void OverviewView::setData(int baseWidth, int baseHeight, std::unordered_mapwidth() / width; qreal h_scale = (qreal)viewport()->height() / height; @@ -34,6 +34,11 @@ void OverviewView::refreshView() current_scale = h_scale; } center(); +} + +void OverviewView::refreshView() +{ + scaleAndCenter(); viewport()->update(); } @@ -94,6 +99,7 @@ void OverviewView::mousePressEvent(QMouseEvent *event) qreal x = event->localPos().x() - w / 2; qreal y = event->localPos().y() - h / 2; rangeRect = QRectF(x, y, w, h); + useCache = true; viewport()->update(); emit mouseMoved(); mouseContainsRect(event); @@ -113,6 +119,7 @@ void OverviewView::mouseMoveEvent(QMouseEvent *event) qreal x = event->localPos().x() - initialDiff.x(); qreal y = event->localPos().y() - initialDiff.y(); rangeRect = QRectF(x, y, rangeRect.width(), rangeRect.height()); + useCache = true; viewport()->update(); emit mouseMoved(); } diff --git a/src/widgets/OverviewView.h b/src/widgets/OverviewView.h index 782ce085..21848432 100644 --- a/src/widgets/OverviewView.h +++ b/src/widgets/OverviewView.h @@ -36,7 +36,7 @@ public: public slots: /** - * @brief refresh the view and adjust the scale + * @brief scale and center all nodes in, then run update */ void refreshView(); @@ -79,6 +79,11 @@ private: */ QPointF initialDiff; + /** + * @brief calculate the scale to fit the all nodes in and center them in the viewport + */ + void scaleAndCenter(); + /** * @brief draw the computed blocks passed by Graph */