Refactor Refresh and Display of Overview (#1453)

This commit is contained in:
Florian Märkl 2019-04-14 14:18:24 +02:00 committed by GitHub
parent 34387c74b1
commit 7eb62a976c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 276 additions and 228 deletions

View File

@ -240,18 +240,23 @@ void MainWindow::initDocks()
hexdumpDock = new HexdumpWidget(this, ui->actionHexdump); hexdumpDock = new HexdumpWidget(this, ui->actionHexdump);
pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode); pseudocodeDock = new PseudocodeWidget(this, ui->actionPseudocode);
consoleDock = new ConsoleWidget(this, ui->actionConsole); consoleDock = new ConsoleWidget(this, ui->actionConsole);
overviewDock = new OverviewWidget(this, ui->actionOverview); overviewDock = new OverviewWidget(this, ui->actionOverview);
overviewDock->hide(); 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) { connect(ui->actionOverview, &QAction::toggled, [this](bool checked) {
if (checked) { if (checked) {
overviewDock->setUserClosed(false); overviewDock->show();
forceUpdateOverview(); } else {
if (targetGraphDock) { overviewDock->hide();
toggleOverview(true, targetGraphDock);
}
} }
}); });
ui->actionOverview->setChecked(overviewDock->getUserOpened());
graphDock = new GraphWidget(this, ui->actionGraph);
sectionsDock = new SectionsWidget(this, ui->actionSections); sectionsDock = new SectionsWidget(this, ui->actionSections);
segmentsDock = new SegmentsWidget(this, ui->actionSegments); segmentsDock = new SegmentsWidget(this, ui->actionSegments);
entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints); entrypointDock = new EntrypointWidget(this, ui->actionEntrypoints);
@ -297,124 +302,9 @@ void MainWindow::toggleOverview(bool visibility, GraphWidget *targetGraph)
if (!overviewDock) { if (!overviewDock) {
return; return;
} }
ui->actionOverview->setEnabled(visibility); if (visibility) {
if (overviewDock->getUserClosed() || !visibility) { overviewDock->setTargetGraphWidget(targetGraph);
return;
} }
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() void MainWindow::updateTasksIndicator()
@ -931,12 +821,6 @@ void MainWindow::enableDebugWidgetsMenu(bool enable)
ui->menuAddDebugWidgets->setEnabled(enable); ui->menuAddDebugWidgets->setEnabled(enable);
} }
void MainWindow::enableOverviewMenu(bool enable)
{
ui->actionOverview->setEnabled(enable);
ui->actionOverview->setChecked(enable);
}
void MainWindow::resetToDefaultLayout() void MainWindow::resetToDefaultLayout()
{ {
hideAllDocks(); hideAllDocks();
@ -1005,7 +889,6 @@ void MainWindow::on_actionFunctionsRename_triggered()
void MainWindow::on_actionDefault_triggered() void MainWindow::on_actionDefault_triggered()
{ {
disconnectOverview();
if (core->currentlyDebugging) { if (core->currentlyDebugging) {
resetToDebugLayout(); resetToDebugLayout();
} else { } else {

View File

@ -186,13 +186,6 @@ private slots:
void changeDebugView(); void changeDebugView();
void changeDefinedView(); void changeDefinedView();
void disconnectOverview();
void updateOverview();
void forceUpdateOverview();
void updateOverviewAddr();
void drawOverview();
void adjustGraph();
private: private:
CutterCore *core; CutterCore *core;
@ -216,7 +209,6 @@ private:
HexdumpWidget *hexdumpDock = nullptr; HexdumpWidget *hexdumpDock = nullptr;
PseudocodeWidget *pseudocodeDock = nullptr; PseudocodeWidget *pseudocodeDock = nullptr;
GraphWidget *graphDock = nullptr; GraphWidget *graphDock = nullptr;
GraphWidget *targetGraphDock = nullptr;
OverviewWidget *overviewDock = nullptr; OverviewWidget *overviewDock = nullptr;
EntrypointWidget *entrypointDock = nullptr; EntrypointWidget *entrypointDock = nullptr;
FunctionsWidget *functionsDock = nullptr; FunctionsWidget *functionsDock = nullptr;
@ -265,7 +257,6 @@ private:
void showZenDocks(); void showZenDocks();
void showDebugDocks(); void showDebugDocks();
void enableDebugWidgetsMenu(bool enable); void enableDebugWidgetsMenu(bool enable);
void enableOverviewMenu(bool enable);
void toggleDockWidget(QDockWidget *dock_widget, bool show); void toggleDockWidget(QDockWidget *dock_widget, bool show);

View File

@ -190,7 +190,7 @@ void DisassemblerGraphView::loadCurrentGraph()
highlight_token = nullptr; highlight_token = nullptr;
} }
bool emptyGraph = functions.isEmpty(); emptyGraph = functions.isEmpty();
if (emptyGraph) { if (emptyGraph) {
// If there's no function to print, just add a message // If there's no function to print, just add a message
if (!emptyText) { if (!emptyText) {
@ -375,8 +375,8 @@ void DisassemblerGraphView::initFont()
void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block) void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
{ {
int blockX = block.x - offset.x(); int blockX = block.x - getViewOffset().x();
int blockY = block.y - offset.y(); int blockY = block.y - getViewOffset().y();
p.setPen(Qt::black); p.setPen(Qt::black);
p.setBrush(Qt::gray); p.setBrush(Qt::gray);
@ -517,7 +517,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
qreal lineHeightRender = charHeight; qreal lineHeightRender = charHeight;
for (auto &line : db.header_text.lines) { for (auto &line : db.header_text.lines) {
qreal lineYRender = y; qreal lineYRender = y;
lineYRender *= current_scale; lineYRender *= getViewScale();
// Check if line does NOT intersects with view area // Check if line does NOT intersects with view area
if (0 > lineYRender + lineHeightRender if (0 > lineYRender + lineHeightRender
|| render_height < lineYRender) { || render_height < lineYRender) {
@ -543,7 +543,7 @@ void DisassemblerGraphView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
} }
for (auto &line : instr.text.lines) { for (auto &line : instr.text.lines) {
qreal lineYRender = y; qreal lineYRender = y;
lineYRender *= current_scale; lineYRender *= getViewScale();
if (0 > lineYRender + lineHeightRender if (0 > lineYRender + lineHeightRender
|| render_height < lineYRender) { || render_height < lineYRender) {
y += charHeight; y += charHeight;
@ -705,16 +705,17 @@ void DisassemblerGraphView::zoom(QPointF mouseRelativePos, double velocity)
{ {
mouseRelativePos.rx() *= size().width(); mouseRelativePos.rx() *= size().width();
mouseRelativePos.ry() *= size().height(); mouseRelativePos.ry() *= size().height();
mouseRelativePos /= current_scale; mouseRelativePos /= getViewScale();
auto globalMouse = mouseRelativePos + offset; auto globalMouse = mouseRelativePos + getViewOffset();
mouseRelativePos *= current_scale; mouseRelativePos *= getViewScale();
current_scale *= std::pow(1.25, velocity); qreal newScale = getViewScale() * std::pow(1.25, velocity);
current_scale = std::max(current_scale, 0.3); newScale = std::max(newScale, 0.3);
mouseRelativePos /= current_scale; mouseRelativePos /= newScale;
setViewScale(newScale);
// Adjusting offset, so that zooming will be approaching to the cursor. // Adjusting offset, so that zooming will be approaching to the cursor.
offset = globalMouse.toPoint() - mouseRelativePos.toPoint(); setViewOffset(globalMouse.toPoint() - mouseRelativePos.toPoint());
viewport()->update(); viewport()->update();
emit viewZoomed(); emit viewZoomed();
@ -722,7 +723,7 @@ void DisassemblerGraphView::zoom(QPointF mouseRelativePos, double velocity)
void DisassemblerGraphView::zoomReset() void DisassemblerGraphView::zoomReset()
{ {
current_scale = 1.0; setViewScale(1.0);
viewport()->update(); viewport()->update();
emit viewZoomed(); emit viewZoomed();
} }
@ -992,6 +993,12 @@ void DisassemblerGraphView::wheelEvent(QWheelEvent *event)
emit graphMoved(); emit graphMoved();
} }
void DisassemblerGraphView::resizeEvent(QResizeEvent *event)
{
GraphView::resizeEvent(event);
emit resized();
}
void DisassemblerGraphView::paintEvent(QPaintEvent *event) void DisassemblerGraphView::paintEvent(QPaintEvent *event)
{ {
// DisassemblerGraphView is always dirty // DisassemblerGraphView is always dirty

View File

@ -129,6 +129,7 @@ protected:
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override; void wheelEvent(QWheelEvent *event) override;
void resizeEvent(QResizeEvent *event) override;
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
@ -196,6 +197,10 @@ signals:
void viewRefreshed(); void viewRefreshed();
void viewZoomed(); void viewZoomed();
void graphMoved(); void graphMoved();
void resized();
public:
bool isGraphEmpty() { return emptyGraph; }
}; };
#endif // DISASSEMBLERGRAPHVIEW_H #endif // DISASSEMBLERGRAPHVIEW_H

View File

@ -143,6 +143,18 @@ void GraphView::beginMouseDrag(QMouseEvent *event)
viewport()->grabMouse(); 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() QSize GraphView::getCacheSize()
{ {
return return
@ -214,10 +226,6 @@ void GraphView::paintEvent(QPaintEvent *)
QPainter p(viewport()); QPainter p(viewport());
p.drawPixmap(target, pixmap, source); p.drawPixmap(target, pixmap, source);
} }
if(cacheWasDirty) { // TODO: does this condition make sense?
emit refreshBlock();
}
} }
void GraphView::paintGraphCache() void GraphView::paintGraphCache()
@ -341,20 +349,27 @@ void GraphView::paintGraphCache()
void GraphView::center() void GraphView::center()
{ {
centerX(); centerX(false);
centerY(); centerY(false);
emit viewOffsetChanged(offset);
} }
void GraphView::centerX() void GraphView::centerX(bool emitSignal)
{ {
offset.rx() = -((viewport()->width() - width * current_scale) / 2); offset.rx() = -((viewport()->width() - width * current_scale) / 2);
offset.rx() /= current_scale; 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() = -((viewport()->height() - height * current_scale) / 2);
offset.ry() /= current_scale; offset.ry() /= current_scale;
if (emitSignal) {
emit viewOffsetChanged(offset);
}
} }
void GraphView::showBlock(GraphBlock &block) void GraphView::showBlock(GraphBlock &block)
@ -365,16 +380,17 @@ void GraphView::showBlock(GraphBlock &block)
void GraphView::showBlock(GraphBlock *block) void GraphView::showBlock(GraphBlock *block)
{ {
if (width * current_scale <= viewport()->width()) { if (width * current_scale <= viewport()->width()) {
centerX(); centerX(false);
} else { } else {
int render_width = viewport()->width() / current_scale; int render_width = viewport()->width() / current_scale;
offset.rx() = block->x - ((render_width - block->width) / 2); offset.rx() = block->x - ((render_width - block->width) / 2);
} }
if (height * current_scale <= viewport()->height()) { if (height * current_scale <= viewport()->height()) {
centerY(); centerY(false);
} else { } else {
offset.ry() = block->y - 30; offset.ry() = block->y - 30;
} }
emit viewOffsetChanged(offset);
blockTransitionedTo(block); blockTransitionedTo(block);
viewport()->update(); viewport()->update();
} }
@ -463,6 +479,7 @@ void GraphView::mouseMoveEvent(QMouseEvent *event)
if (scroll_mode) { if (scroll_mode) {
offset.rx() += (scroll_base_x - event->x()) / current_scale; offset.rx() += (scroll_base_x - event->x()) / current_scale;
offset.ry() += (scroll_base_y - event->y()) / current_scale; offset.ry() += (scroll_base_y - event->y()) / current_scale;
emit viewOffsetChanged(offset);
scroll_base_x = event->x(); scroll_base_x = event->x();
scroll_base_y = event->y(); scroll_base_y = event->y();
viewport()->update(); viewport()->update();
@ -510,6 +527,7 @@ void GraphView::keyPressEvent(QKeyEvent* event)
} }
offset.rx() += dx; offset.rx() += dx;
offset.ry() += dy; offset.ry() += dy;
emit viewOffsetChanged(offset);
viewport()->update(); viewport()->update();
event->accept(); event->accept();
} }
@ -540,6 +558,7 @@ void GraphView::wheelEvent(QWheelEvent *event)
delta /= current_scale; delta /= current_scale;
offset += delta; offset += delta;
emit viewOffsetChanged(offset);
viewport()->update(); viewport()->update();
event->accept(); event->accept();

View File

@ -24,8 +24,10 @@ class QOpenGLWidget;
class GraphView : public QAbstractScrollArea class GraphView : public QAbstractScrollArea
{ {
Q_OBJECT Q_OBJECT
signals: signals:
void refreshBlock(); void viewOffsetChanged(QPoint offset);
void viewScaleChanged(qreal scale);
public: public:
using GraphBlock = GraphLayout::GraphBlock; using GraphBlock = GraphLayout::GraphBlock;
@ -44,17 +46,12 @@ public:
void showBlock(GraphBlock &block); void showBlock(GraphBlock &block);
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 * @brief keep the current addr of the fcn of Graph
* Everytime overview updates its contents, it compares this value with the one in 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. * 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: protected:
std::unordered_map<ut64, GraphBlock> blocks; std::unordered_map<ut64, GraphBlock> blocks;
@ -91,17 +88,22 @@ protected:
void paintEvent(QPaintEvent *event) override; void paintEvent(QPaintEvent *event) override;
void center();
void centerX();
void centerY();
int width = 0; int width = 0;
int height = 0; int height = 0;
private: private:
void centerX(bool emitSignal);
void centerY(bool emitSignal);
void paintGraphCache(); void paintGraphCache();
bool checkPointClicked(QPointF &point, int x, int y, bool above_y = false); 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; ut64 entry;
std::unique_ptr<GraphLayout> graphLayoutSystem; std::unique_ptr<GraphLayout> graphLayoutSystem;
@ -141,6 +143,16 @@ private:
QPolygonF recalculatePolygon(QPolygonF polygon); QPolygonF recalculatePolygon(QPolygonF polygon);
void beginMouseDrag(QMouseEvent *event); 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 #endif // GRAPHVIEW_H

View File

@ -51,7 +51,7 @@ QWidget *GraphWidget::widgetToFocusOnRaise()
void GraphWidget::closeEvent(QCloseEvent *event) void GraphWidget::closeEvent(QCloseEvent *event)
{ {
CutterDockWidget::closeEvent(event); CutterDockWidget::closeEvent(event);
emit graphClose(); emit graphClosed();
} }
DisassemblerGraphView *GraphWidget::getGraphView() const DisassemblerGraphView *GraphWidget::getGraphView() const

View File

@ -17,7 +17,7 @@ public:
DisassemblerGraphView *getGraphView() const; DisassemblerGraphView *getGraphView() const;
signals: signals:
void graphClose(); void graphClosed();
protected: protected:
QWidget *widgetToFocusOnRaise() override; QWidget *widgetToFocusOnRaise() override;

View File

@ -24,6 +24,7 @@ void OverviewView::setData(int baseWidth, int baseHeight,
edgeConfigurations = baseEdgeConfigurations; edgeConfigurations = baseEdgeConfigurations;
scaleAndCenter(); scaleAndCenter();
setCacheDirty(); setCacheDirty();
viewport()->update();
} }
OverviewView::~OverviewView() OverviewView::~OverviewView()
@ -32,11 +33,9 @@ OverviewView::~OverviewView()
void OverviewView::scaleAndCenter() void OverviewView::scaleAndCenter()
{ {
current_scale = (qreal)viewport()->width() / width; qreal wScale = (qreal)viewport()->width() / width;
qreal h_scale = (qreal)viewport()->height() / height; qreal hScale = (qreal)viewport()->height() / height;
if (current_scale > h_scale) { setViewScale(std::min(wScale, hScale));
current_scale = h_scale;
}
center(); center();
} }
@ -48,8 +47,8 @@ void OverviewView::refreshView()
void OverviewView::drawBlock(QPainter &p, GraphView::GraphBlock &block) void OverviewView::drawBlock(QPainter &p, GraphView::GraphBlock &block)
{ {
int blockX = block.x - offset.x(); int blockX = block.x - getViewOffset().x();
int blockY = block.y - offset.y(); int blockY = block.y - getViewOffset().y();
p.setPen(Qt::black); p.setPen(Qt::black);
p.setBrush(Qt::gray); p.setBrush(Qt::gray);
@ -138,7 +137,7 @@ GraphView::EdgeConfiguration OverviewView::edgeConfiguration(GraphView::GraphBlo
auto baseEcIt = edgeConfigurations.find({from.entry, to->entry}); auto baseEcIt = edgeConfigurations.find({from.entry, to->entry});
if (baseEcIt != edgeConfigurations.end()) if (baseEcIt != edgeConfigurations.end())
ec = baseEcIt->second; ec = baseEcIt->second;
ec.width_scale = current_scale; ec.width_scale = getViewScale();
return ec; return ec;
} }
@ -149,3 +148,9 @@ void OverviewView::colorsUpdatedSlot()
backgroundColor = ConfigColor("gui.background"); backgroundColor = ConfigColor("gui.background");
refreshView(); refreshView();
} }
void OverviewView::setRangeRect(QRectF rect)
{
rangeRect = rect;
viewport()->update();
}

View File

@ -22,11 +22,6 @@ public:
OverviewView(QWidget *parent); OverviewView(QWidget *parent);
~OverviewView() override; ~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 * @brief Graph access this function to set minimum set of the data
* @param baseWidth width of Graph when it computed the blocks * @param baseWidth width of Graph when it computed the blocks
@ -87,6 +82,11 @@ private:
*/ */
QPointF initialDiff; 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 * @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 * @brief edgeConfigurations edge styles computed by DisassemblerGraphView
*/ */
DisassemblerGraphView::EdgeConfigurationMapping edgeConfigurations; DisassemblerGraphView::EdgeConfigurationMapping edgeConfigurations;
public:
QRectF getRangeRect() { return rangeRect; }
void setRangeRect(QRectF rect);
}; };
#endif // OVERVIEWVIEW_H #endif // OVERVIEWVIEW_H

View File

@ -1,5 +1,6 @@
#include "core/MainWindow.h" #include "core/MainWindow.h"
#include "OverviewWidget.h" #include "OverviewWidget.h"
#include "GraphWidget.h"
#include "OverviewView.h" #include "OverviewView.h"
OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) : OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) :
@ -10,14 +11,12 @@ OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) :
setAllowedAreas(Qt::AllDockWidgetAreas); setAllowedAreas(Qt::AllDockWidgetAreas);
graphView = new OverviewView(this); graphView = new OverviewView(this);
setWidget(graphView); setWidget(graphView);
refreshDeferrer = createRefreshDeferrer([this]() { targetGraphWidget = nullptr;
updateContents();
});
connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) { connect(graphView, SIGNAL(mouseMoved()), this, SLOT(updateTargetView()));
if (visibility) {
updateContents(); graphDataRefreshDeferrer = createRefreshDeferrer([this]() {
} updateGraphData();
}); });
} }
@ -26,35 +25,124 @@ OverviewWidget::~OverviewWidget() {}
void OverviewWidget::resizeEvent(QResizeEvent *event) void OverviewWidget::resizeEvent(QResizeEvent *event)
{ {
graphView->refreshView(); graphView->refreshView();
updateRangeRect();
QDockWidget::resizeEvent(event); QDockWidget::resizeEvent(event);
emit resized(); emit resized();
} }
void OverviewWidget::updateContents() void OverviewWidget::showEvent(QShowEvent *event)
{ {
if (!refreshDeferrer->attemptRefresh(nullptr)) { CutterDockWidget::showEvent(event);
return; setUserOpened(true);
}
graphView->refreshView();
} }
void OverviewWidget::closeEvent(QCloseEvent *event) void OverviewWidget::closeEvent(QCloseEvent *event)
{ {
CutterDockWidget::closeEvent(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));
}
} }

View File

@ -5,6 +5,7 @@
class MainWindow; class MainWindow;
class OverviewView; class OverviewView;
class GraphWidget;
class OverviewWidget : public CutterDockWidget class OverviewWidget : public CutterDockWidget
{ {
@ -14,45 +15,78 @@ public:
explicit OverviewWidget(MainWindow *main, QAction *action = nullptr); explicit OverviewWidget(MainWindow *main, QAction *action = nullptr);
~OverviewWidget(); ~OverviewWidget();
OverviewView *getGraphView() const;
/*
* @brief if user closed this widget explicitly
*/
bool getUserClosed() const;
void setUserClosed(bool value);
private: 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 * @brief this takes care of scaling the overview when the widget is resized
*/ */
void resizeEvent(QResizeEvent *event) override; void resizeEvent(QResizeEvent *event) override;
void setIsAvailable(bool isAvailable);
void setUserOpened(bool userOpened);
private slots: private slots:
/** void showEvent(QShowEvent *event) override;
* @brief update the overview
*/
void updateContents();
/*
* @brief override closeEvent to emit graphClose
*/
void closeEvent(QCloseEvent *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: signals:
/** /**
* @brief emit signal to update the rect * @brief emit signal to update the rect
*/ */
void resized(); void resized();
/*
* @brief emit signal to notify when this widget is closed /**
* @sa getIsAvailable()
*/ */
void graphClose(); void isAvailableChanged(bool isAvailable);
private: /**
OverviewView *graphView; * @sa getUserOpened()
bool userClosed = false; */
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 #endif // OverviewWIDGET_H