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);
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 {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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();

View File

@ -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

View File

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

View File

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

View File

@ -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();
}

View File

@ -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

View File

@ -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));
}
}

View File

@ -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