cutter/src/widgets/OverviewWidget.cpp

171 lines
6.1 KiB
C++

#include "core/MainWindow.h"
#include "OverviewWidget.h"
#include "GraphWidget.h"
#include "OverviewView.h"
OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) :
CutterDockWidget(main, action)
{
setWindowTitle("Graph Overview");
setObjectName("Graph Overview");
setAllowedAreas(Qt::AllDockWidgetAreas);
graphView = new OverviewView(this);
setWidget(graphView);
targetGraphWidget = nullptr;
connect(graphView, SIGNAL(mouseMoved()), this, SLOT(updateTargetView()));
graphDataRefreshDeferrer = createRefreshDeferrer([this]() {
updateGraphData();
});
// Zoom shortcuts
QShortcut *shortcut_zoom_in = new QShortcut(QKeySequence(Qt::Key_Plus), this);
shortcut_zoom_in->setContext(Qt::WidgetWithChildrenShortcut);
connect(shortcut_zoom_in, &QShortcut::activated, this, [this](){ zoomTarget(1); });
QShortcut *shortcut_zoom_out = new QShortcut(QKeySequence(Qt::Key_Minus), this);
shortcut_zoom_out->setContext(Qt::WidgetWithChildrenShortcut);
connect(shortcut_zoom_out, &QShortcut::activated, this, [this](){ zoomTarget(-1); });
}
OverviewWidget::~OverviewWidget() {}
void OverviewWidget::resizeEvent(QResizeEvent *event)
{
graphView->refreshView();
updateRangeRect();
QDockWidget::resizeEvent(event);
emit resized();
}
void OverviewWidget::showEvent(QShowEvent *event)
{
CutterDockWidget::showEvent(event);
setUserOpened(true);
}
void OverviewWidget::closeEvent(QCloseEvent *event)
{
CutterDockWidget::closeEvent(event);
setUserOpened(false);
}
void OverviewWidget::setIsAvailable(bool isAvailable)
{
if (this->isAvailable == isAvailable) {
return;
}
this->isAvailable = isAvailable;
if(!isAvailable) {
hide();
} else if(userOpened) {
show();
}
emit isAvailableChanged(isAvailable);
}
void OverviewWidget::setUserOpened(bool userOpened)
{
if (this->userOpened == userOpened) {
return;
}
this->userOpened = userOpened;
emit userOpenedChanged(userOpened);
}
void OverviewWidget::zoomTarget(int d)
{
if (!targetGraphWidget) {
return;
}
targetGraphWidget->getGraphView()->zoom(QPointF(0.5, 0.5), d);
}
void OverviewWidget::setTargetGraphWidget(GraphWidget *widget)
{
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::wheelEvent(QWheelEvent *event)
{
zoomTarget(event->angleDelta().y() / 90);
graphView->centreRect();
}
void OverviewWidget::targetClosed()
{
setTargetGraphWidget(nullptr);
}
void OverviewWidget::updateTargetView()
{
if (!targetGraphWidget) {
return;
}
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()) {
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));
}
}