From b25afecc2ce2a4b95e10d4bc7ea36dad32bf1af2 Mon Sep 17 00:00:00 2001 From: Vanellope Date: Fri, 25 Jan 2019 02:13:04 +0900 Subject: [PATCH] Graph Overview (#1120) Added a Graph Overview --- src/Cutter.pro | 4 + src/MainWindow.cpp | 20 +++- src/MainWindow.h | 5 +- src/MainWindow.ui | 9 ++ src/common/Configuration.cpp | 3 + src/widgets/DisassemblerGraphView.cpp | 1 + src/widgets/DisassemblerGraphView.h | 7 ++ src/widgets/GraphView.cpp | 3 + src/widgets/GraphView.h | 37 ++++--- src/widgets/GraphWidget.cpp | 92 +++++++++++++++- src/widgets/GraphWidget.h | 13 ++- src/widgets/OverviewView.cpp | 148 ++++++++++++++++++++++++++ src/widgets/OverviewView.h | 112 +++++++++++++++++++ src/widgets/OverviewWidget.cpp | 33 ++++++ src/widgets/OverviewWidget.h | 28 +++++ 15 files changed, 492 insertions(+), 23 deletions(-) create mode 100644 src/widgets/OverviewView.cpp create mode 100644 src/widgets/OverviewView.h create mode 100644 src/widgets/OverviewWidget.cpp create mode 100644 src/widgets/OverviewWidget.h diff --git a/src/Cutter.pro b/src/Cutter.pro index 83f97c61..6085c098 100644 --- a/src/Cutter.pro +++ b/src/Cutter.pro @@ -128,6 +128,7 @@ SOURCES += \ Main.cpp \ Cutter.cpp \ widgets/DisassemblerGraphView.cpp \ + widgets/OverviewView.cpp \ common/RichTextPainter.cpp \ dialogs/InitialOptionsDialog.cpp \ dialogs/AboutDialog.cpp \ @@ -192,6 +193,7 @@ SOURCES += \ widgets/CutterDockWidget.cpp \ widgets/CutterTreeWidget.cpp \ widgets/GraphWidget.cpp \ + widgets/OverviewWidget.cpp \ common/JsonTreeItem.cpp \ common/JsonModel.cpp \ dialogs/VersionInfoDialog.cpp \ @@ -229,6 +231,7 @@ SOURCES += \ HEADERS += \ Cutter.h \ widgets/DisassemblerGraphView.h \ + widgets/OverviewView.h \ common/RichTextPainter.h \ common/CachedFontMetrics.h \ dialogs/AboutDialog.h \ @@ -294,6 +297,7 @@ HEADERS += \ widgets/CutterDockWidget.h \ widgets/CutterTreeWidget.h \ widgets/GraphWidget.h \ + widgets/OverviewWidget.h \ common/JsonTreeItem.h \ common/JsonModel.h \ dialogs/VersionInfoDialog.h \ diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index 1bb4c390..14006399 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -54,7 +54,9 @@ // Widgets Headers #include "widgets/DisassemblerGraphView.h" +#include "widgets/GraphView.h" #include "widgets/GraphWidget.h" +#include "widgets/OverviewWidget.h" #include "widgets/FunctionsWidget.h" #include "widgets/SectionsWidget.h" #include "widgets/SegmentsWidget.h" @@ -182,7 +184,17 @@ void MainWindow::initUI() consoleDock = new ConsoleWidget(this, ui->actionConsole); // Add graph view as dockable - graphDock = new GraphWidget(this, ui->actionGraph); + overviewDock = new OverviewWidget(this, ui->actionOverview); + graphDock = new GraphWidget(this, overviewDock, ui->actionGraph); + + connect(graphDock, &QDockWidget::visibilityChanged, this, [ = ](bool visible) { + ui->actionOverview->setChecked(visible); + if (visible) { + overviewDock->show(); + } else { + overviewDock->hide(); + } + }); sectionsDock = new SectionsWidget(this, ui->actionSections); segmentsDock = new SegmentsWidget(this, ui->actionSegments); @@ -558,9 +570,11 @@ void MainWindow::restoreDocks() { // In the upper half the functions are the first widget addDockWidget(Qt::TopDockWidgetArea, functionsDock); + addDockWidget(Qt::TopDockWidgetArea, overviewDock); // Function | Dashboard - splitDockWidget(functionsDock, dashboardDock, Qt::Horizontal); + splitDockWidget(overviewDock, dashboardDock, Qt::Horizontal); + splitDockWidget(functionsDock, overviewDock, Qt::Vertical); // In the lower half the console is the first widget addDockWidget(Qt::BottomDockWidgetArea, consoleDock); @@ -688,8 +702,10 @@ void MainWindow::resetToDefaultLayout() // Ugly workaround to set the default widths of functions docks // if anyone finds a way to do this cleaner that also works, feel free to change it! auto restoreFunctionDock = qhelpers::forceWidth(functionsDock->widget(), 200); + auto restoreOverviewDock = qhelpers::forceWidth(overviewDock->widget(), 200); qApp->processEvents(); restoreFunctionDock.restoreWidth(functionsDock->widget()); + restoreOverviewDock.restoreWidth(overviewDock->widget()); core->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly); } diff --git a/src/MainWindow.h b/src/MainWindow.h index d288facf..061455c7 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -5,6 +5,8 @@ #include "Cutter.h" // only needed for ut64 #include "widgets/DisassemblyWidget.h" +#include "widgets/GraphWidget.h" +#include "widgets/OverviewWidget.h" #include "widgets/StackWidget.h" #include "widgets/RegistersWidget.h" #include "widgets/BacktraceWidget.h" @@ -103,6 +105,7 @@ public: void updateDockActionChecked(QAction * action); + OverviewWidget *overviewDock = nullptr; public slots: void finalizeOpen(); @@ -199,7 +202,7 @@ private: DisassemblyWidget *disassemblyDock = nullptr; HexdumpWidget *hexdumpDock = nullptr; PseudocodeWidget *pseudocodeDock = nullptr; - QDockWidget *graphDock = nullptr; + GraphWidget *graphDock = nullptr; EntrypointWidget *entrypointDock = nullptr; FunctionsWidget *functionsDock = nullptr; ImportsWidget *importsDock = nullptr; diff --git a/src/MainWindow.ui b/src/MainWindow.ui index 2af8acfe..b0f8679a 100644 --- a/src/MainWindow.ui +++ b/src/MainWindow.ui @@ -194,6 +194,7 @@ QToolTip { + @@ -933,6 +934,14 @@ QToolTip { Graph + + + true + + + Graph Overview + + true diff --git a/src/common/Configuration.cpp b/src/common/Configuration.cpp index d2181fad..7087d751 100644 --- a/src/common/Configuration.cpp +++ b/src/common/Configuration.cpp @@ -196,6 +196,7 @@ void Configuration::loadBaseThemeNative() setColor("gui.breakpoint_background", QColor(233, 143, 143)); setColor("gui.item_invalid", QColor(155, 155, 155)); setColor("gui.item_unsafe", QColor(255, 129, 123)); + setColor("gui.overview.node", QColor(200, 200, 200)); } void Configuration::loadNativeTheme() @@ -268,6 +269,8 @@ void Configuration::loadBaseThemeDark() // RIP line selection in debug setColor("highlightPC", QColor(87, 26, 7)); setColor("gui.breakpoint_background", QColor(140, 76, 76)); + + setColor("gui.overview.node", QColor(100, 100, 100)); } void Configuration::loadDarkTheme() diff --git a/src/widgets/DisassemblerGraphView.cpp b/src/widgets/DisassemblerGraphView.cpp index 5c0d6dcd..2bd37639 100644 --- a/src/widgets/DisassemblerGraphView.cpp +++ b/src/widgets/DisassemblerGraphView.cpp @@ -157,6 +157,7 @@ void DisassemblerGraphView::refreshView() initFont(); loadCurrentGraph(); viewport()->update(); + emit viewRefreshed(); } void DisassemblerGraphView::loadCurrentGraph() diff --git a/src/widgets/DisassemblerGraphView.h b/src/widgets/DisassemblerGraphView.h index 91438ce2..d1ee656d 100644 --- a/src/widgets/DisassemblerGraphView.h +++ b/src/widgets/DisassemblerGraphView.h @@ -128,6 +128,10 @@ public: bool isGraphEmpty(); QTextEdit *header = nullptr; + int getWidth() { return width; } + int getHeight() { return height; } + + std::unordered_map getBlocks() { return blocks; } public slots: void refreshView(); void colorsUpdatedSlot(); @@ -212,6 +216,9 @@ private: QLabel *emptyText = nullptr; SyntaxHighlighter *highlighter = nullptr; + +signals: + void viewRefreshed(); }; #endif // DISASSEMBLERGRAPHVIEW_H diff --git a/src/widgets/GraphView.cpp b/src/widgets/GraphView.cpp index ee226b50..76bb31d7 100644 --- a/src/widgets/GraphView.cpp +++ b/src/widgets/GraphView.cpp @@ -469,6 +469,7 @@ void GraphView::paintEvent(QPaintEvent *event) QPen pen(edge.color); // if(blockSelected) // pen.setStyle(Qt::DashLine); + pen.setWidth(pen.width()/ec.width_scale); p.setPen(pen); p.setBrush(edge.color); p.drawPolyline(edge.polyline); @@ -482,6 +483,8 @@ void GraphView::paintEvent(QPaintEvent *event) } } } + + emit refreshBlock(); } // Prepare graph diff --git a/src/widgets/GraphView.h b/src/widgets/GraphView.h index 77d15aa7..f48c4710 100644 --- a/src/widgets/GraphView.h +++ b/src/widgets/GraphView.h @@ -24,6 +24,10 @@ class GraphView : public QAbstractScrollArea Wide, Narrow, }; + +signals: + void refreshBlock(); + public: struct GraphBlock; @@ -84,6 +88,7 @@ public: QColor color = QColor(128, 128, 128); bool start_arrow = false; bool end_arrow = true; + qreal width_scale = 1.0; }; explicit GraphView(QWidget *parent); @@ -94,6 +99,12 @@ public: void showBlock(GraphBlock &block, bool animated = false); void showBlock(GraphBlock *block, bool animated = false); + // Zoom data + qreal current_scale = 1.0; + + int unscrolled_render_offset_x = 0; + int unscrolled_render_offset_y = 0; + protected: std::unordered_map blocks; QColor backgroundColor = QColor(Qt::white); @@ -104,11 +115,6 @@ protected: // Padding inside the block int block_padding = 16; - // Zoom data - double current_scale = 1.0; - - int unscrolled_render_offset_x = 0; - int unscrolled_render_offset_y = 0; void addBlock(GraphView::GraphBlock block); void setEntry(ut64 e); @@ -127,6 +133,16 @@ protected: void adjustSize(int new_width, int new_height, QPoint mouse = QPoint(0, 0)); bool event(QEvent *event) override; + + void resizeEvent(QResizeEvent *event) override; + // Mouse events + void mousePressEvent(QMouseEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; + void mouseReleaseEvent(QMouseEvent *event) override; + void mouseDoubleClickEvent(QMouseEvent *event) override; + + int width = 0; + int height = 0; private: bool checkPointClicked(QPointF &point, int x, int y, bool above_y = false); @@ -138,8 +154,6 @@ private: // Layout type LayoutType layoutType = LayoutType::Medium; - int width = 0; - int height = 0; bool ready = false; // Scrolling data @@ -163,15 +177,6 @@ private: int findVertEdgeIndex(EdgesVector &edges, int col, int min_row, int max_row); GraphEdge routeEdge(EdgesVector &horiz_edges, EdgesVector &vert_edges, Matrix &edge_valid, GraphBlock &start, GraphBlock &end, QColor color); - -private slots: - void resizeEvent(QResizeEvent *event) override; - // Mouse events - void mousePressEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseDoubleClickEvent(QMouseEvent *event) override; - }; #endif // GRAPHVIEW_H diff --git a/src/widgets/GraphWidget.cpp b/src/widgets/GraphWidget.cpp index 6c038daa..5c778811 100644 --- a/src/widgets/GraphWidget.cpp +++ b/src/widgets/GraphWidget.cpp @@ -2,14 +2,16 @@ #include "GraphWidget.h" #include "DisassemblerGraphView.h" #include "WidgetShortcuts.h" +#include "OverviewView.h" -GraphWidget::GraphWidget(MainWindow *main, QAction *action) : +GraphWidget::GraphWidget(MainWindow *main, OverviewWidget *overview, QAction *action) : CutterDockWidget(main, action) { this->setObjectName("Graph"); this->setAllowedAreas(Qt::AllDockWidgetAreas); this->graphView = new DisassemblerGraphView(this); this->setWidget(graphView); + this->overviewWidget = overview; // getting the name of the class is implementation defined, and cannot be // used reliably across different compilers. @@ -21,12 +23,17 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) : }); connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) { + toggleOverview(visibility); if (visibility) { Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Graph); this->graphView->header->setFixedWidth(width()); } }); + connect(graphView, &DisassemblerGraphView::viewRefreshed, this, [ = ]() { + overviewWidget->graphView->setData(graphView->getWidth(), graphView->getHeight(), graphView->getBlocks()); + }); + connect(Core(), &CutterCore::raisePrioritizedMemoryWidget, this, [ = ](CutterCore::MemoryWidgetType type) { bool emptyGraph = (type == CutterCore::MemoryWidgetType::Graph && Core()->isGraphEmpty()); @@ -39,3 +46,86 @@ GraphWidget::GraphWidget(MainWindow *main, QAction *action) : } GraphWidget::~GraphWidget() {} + +void GraphWidget::toggleOverview(bool visibility) +{ + if (!overviewWidget) { + return; + } + if (visibility) { + connect(graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview())); + connect(graphView->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustOverview())); + connect(graphView->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustOverview())); + connect(overviewWidget->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph())); + } else { + disconnect(graphView, SIGNAL(refreshBlock()), this, SLOT(adjustOverview())); + disconnect(graphView->horizontalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustOverview())); + disconnect(graphView->verticalScrollBar(), SIGNAL(valueChanged(int)), this, SLOT(adjustOverview())); + disconnect(overviewWidget->graphView, SIGNAL(mouseMoved()), this, SLOT(adjustGraph())); + disableOverviewRect(); + } +} + +void GraphWidget::disableOverviewRect() +{ + if (!overviewWidget) { + return; + } + overviewWidget->graphView->rangeRect = QRectF(0, 0, 0, 0); + overviewWidget->graphView->viewport()->update(); +} + +void GraphWidget::adjustOverview() +{ + if (!overviewWidget) { + return; + } + bool scrollXVisible = graphView->unscrolled_render_offset_x == 0; + bool scrollYVisible = graphView->unscrolled_render_offset_y == 0; + if (!scrollXVisible && !scrollYVisible) { + disableOverviewRect(); + return; + } + qreal x = 0; + qreal y = 0; + qreal w = overviewWidget->graphView->viewport()->width(); + qreal h = overviewWidget->graphView->viewport()->height(); + qreal curScale = overviewWidget->graphView->current_scale; + qreal xoff = overviewWidget->graphView->unscrolled_render_offset_x;; + qreal yoff = overviewWidget->graphView->unscrolled_render_offset_y;; + + w = graphView->viewport()->width(); + h = graphView->viewport()->height(); + + if (scrollXVisible) { + x = graphView->horizontalScrollBar()->value(); + w *= curScale; + } else { + xoff = 0; + } + + if (scrollYVisible) { + y = graphView->verticalScrollBar()->value(); + h *= curScale; + } else { + yoff = 0; + } + x *= curScale; + y *= curScale; + overviewWidget->graphView->rangeRect = QRectF(x + xoff, y + yoff, w, h); + overviewWidget->graphView->viewport()->update(); +} + +void GraphWidget::adjustGraph() +{ + if (!overviewWidget) { + return; + } + int x1 = overviewWidget->graphView->horizontalScrollBar()->value(); + int y1 = overviewWidget->graphView->verticalScrollBar()->value(); + qreal x2 = (overviewWidget->graphView->rangeRect.x() - (qreal)overviewWidget->graphView->unscrolled_render_offset_x)/ overviewWidget->graphView->current_scale; + qreal y2 = (overviewWidget->graphView->rangeRect.y() - (qreal)overviewWidget->graphView->unscrolled_render_offset_y)/ overviewWidget->graphView->current_scale; + + graphView->horizontalScrollBar()->setValue(x1 + x2); + graphView->verticalScrollBar()->setValue(y1 + y2); +} diff --git a/src/widgets/GraphWidget.h b/src/widgets/GraphWidget.h index 314c7a83..f13f14c2 100644 --- a/src/widgets/GraphWidget.h +++ b/src/widgets/GraphWidget.h @@ -5,17 +5,24 @@ class MainWindow; class DisassemblerGraphView; +class OverviewWidget; class GraphWidget : public CutterDockWidget { Q_OBJECT public: - explicit GraphWidget(MainWindow *main, QAction *action = nullptr); - ~GraphWidget() override; - + explicit GraphWidget(MainWindow *main, OverviewWidget *overview, QAction *action = nullptr); + ~GraphWidget(); private: DisassemblerGraphView *graphView; + OverviewWidget *overviewWidget; + + void toggleOverview(bool visibility); + void disableOverviewRect(); +private slots: + void adjustOverview(); + void adjustGraph(); }; #endif // GRAPHWIDGET_H diff --git a/src/widgets/OverviewView.cpp b/src/widgets/OverviewView.cpp new file mode 100644 index 00000000..4382793d --- /dev/null +++ b/src/widgets/OverviewView.cpp @@ -0,0 +1,148 @@ +#include "OverviewView.h" +#include +#include + +#include "Cutter.h" +#include "common/Colors.h" +#include "common/Configuration.h" +#include "common/TempConfig.h" + +OverviewView::OverviewView(QWidget *parent) + : GraphView(parent) +{ + connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot())); + colorsUpdatedSlot(); +} + +void OverviewView::setData(int baseWidth, int baseHeight, std::unordered_map baseBlocks) +{ + width = baseWidth; + height = baseHeight; + blocks = baseBlocks; + refreshView(); +} + +OverviewView::~OverviewView() +{ +} + +void OverviewView::adjustScale() +{ + if (horizontalScrollBar()->maximum() > 0) { + current_scale = (qreal)viewport()->width() / (qreal)(horizontalScrollBar()->maximum() + horizontalScrollBar()->pageStep()); + } + if (verticalScrollBar()->maximum() > 0) { + qreal h_scale = (qreal)viewport()->height() / (qreal)(verticalScrollBar()->maximum() + verticalScrollBar()->pageStep()); + if (current_scale > h_scale) { + current_scale = h_scale; + } + } + adjustSize(viewport()->size().width(), viewport()->size().height()); + viewport()->update(); +} + +void OverviewView::refreshView() +{ + current_scale = 1.0; + viewport()->update(); + adjustSize(viewport()->size().width(), viewport()->size().height()); + adjustScale(); +} + +void OverviewView::drawBlock(QPainter &p, GraphView::GraphBlock &block) +{ + p.setPen(Qt::black); + p.setBrush(Qt::gray); + p.drawRect(block.x, block.y, block.width, block.height); + p.setBrush(QColor(0, 0, 0, 100)); + p.drawRect(block.x + 2, block.y + 2, + block.width, block.height); + p.setPen(QPen(graphNodeColor, 1)); + p.setBrush(disassemblyBackgroundColor); + p.drawRect(block.x, block.y, + block.width, block.height); +} + +void OverviewView::paintEvent(QPaintEvent *event) +{ + GraphView::paintEvent(event); + if (rangeRect.width() == 0 && rangeRect.height() == 0) { + return; + } + QPainter p(viewport()); + p.setPen(Qt::red); + p.drawRect(rangeRect); +} + +void OverviewView::mousePressEvent(QMouseEvent *event) +{ + if (rangeRect.contains(event->pos())) { + mouseActive = true; + initialDiff = QPointF(event->localPos().x() - rangeRect.x(), event->localPos().y() - rangeRect.y()); + return; + } + qreal w = rangeRect.width(); + qreal h = rangeRect.height(); + qreal x = event->localPos().x() - w/2; + qreal y = event->localPos().y() - h/2; + rangeRect = QRectF(x, y, w, h); + viewport()->update(); + emit mouseMoved(); + mousePressEvent(event); +} + +void OverviewView::mouseReleaseEvent(QMouseEvent *event) +{ + mouseActive = false; + GraphView::mouseReleaseEvent(event); +} + +void OverviewView::mouseMoveEvent(QMouseEvent *event) +{ + if (!mouseActive) { + return; + } + qreal x = event->localPos().x() - initialDiff.x(); + qreal y = event->localPos().y() - initialDiff.y(); + qreal w = rangeRect.width(); + qreal h = rangeRect.height(); + qreal real_width = width * current_scale; + qreal real_height = height * current_scale; + qreal max_right = unscrolled_render_offset_x + real_width; + qreal max_bottom = unscrolled_render_offset_y + real_height; + qreal rect_right = x + w; + qreal rect_bottom = y + h; + if (rect_right >= max_right) { + x = real_width - w; + } + if (rect_bottom >= max_bottom) { + y = real_height - h; + } + if (x <= 0) { + x = 0; + } + if (y <= 0) { + y = 0; + } + rangeRect = QRectF(x, y, w, h); + viewport()->update(); + emit mouseMoved(); +} + +GraphView::EdgeConfiguration OverviewView::edgeConfiguration(GraphView::GraphBlock &from, + GraphView::GraphBlock *to) +{ + Q_UNUSED(from); + Q_UNUSED(to); + EdgeConfiguration ec; + ec.width_scale = current_scale; + return ec; +} + +void OverviewView::colorsUpdatedSlot() +{ + disassemblyBackgroundColor = ConfigColor("gui.overview.node"); + graphNodeColor = ConfigColor("gui.border"); + backgroundColor = ConfigColor("gui.background"); + refreshView(); +} diff --git a/src/widgets/OverviewView.h b/src/widgets/OverviewView.h new file mode 100644 index 00000000..6c80770b --- /dev/null +++ b/src/widgets/OverviewView.h @@ -0,0 +1,112 @@ +#ifndef OVERVIEWVIEW_H +#define OVERVIEWVIEW_H + +#include +#include +#include +#include "widgets/GraphView.h" + +class OverviewView : public GraphView +{ + Q_OBJECT + +signals: + /** + * @brief signal when mouse is pressed or moved so that + * Graph can refresh its contents corresponded with Overview + */ + void mouseMoved(); + +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 + * @param baseHeigh height of Graph when it computed the blocks + * @param baseBlocks computed blocks passed by Graph + */ + void setData(int baseWidth, int baseHeight, std::unordered_map baseBlocks); + +public slots: + /** + * @brief refresh the view and adjust the scale + */ + void refreshView(); + +private slots: + /** + * @brief update Colors. + * for example this will be called when the theme is changed. + */ + void colorsUpdatedSlot(); + +protected: + /** + * @brief mousePressEvent to start moving the rect. + */ + void mousePressEvent(QMouseEvent *event) override; + /** + * @brief mouseReleaseEvent to tell not to move the rect anymore. + */ + void mouseReleaseEvent(QMouseEvent *event) override; + /** + * @brief mouseMoveEvent to move the rect. + */ + void mouseMoveEvent(QMouseEvent *event) override; + +private: + /** + * @brief this will be handled in mouse events to move the rect properly + * along with the mouse. + */ + bool mouseActive = false; + + /** + * @brief save the initial distance + * between the point where the mouse was pressed and the point of the rect + * so as to change the rect point properly along with mouse. + */ + QPointF initialDiff; + + /** + * @brief draw the computed blocks passed by Graph + */ + virtual void drawBlock(QPainter &p, GraphView::GraphBlock &block) override; + + /** + * @brief override the edgeConfiguration so as to + * adjust the width of the edges by the scale + * @return EdgeConfiguration + */ + virtual GraphView::EdgeConfiguration edgeConfiguration(GraphView::GraphBlock &from, + GraphView::GraphBlock *to) override; + + /** + * @brief override the paintEvent to draw the rect on Overview + */ + void paintEvent(QPaintEvent *event) override; + + /** + * @brief apply scale properly on the view + */ + void adjustScale(); + + /** + * @brief base background color changing depending on the theme + */ + QColor disassemblyBackgroundColor; + + /** + * @brief color for each node changing depending on the theme + */ + QColor graphNodeColor; +}; + +#endif // OVERVIEWVIEW_H diff --git a/src/widgets/OverviewWidget.cpp b/src/widgets/OverviewWidget.cpp new file mode 100644 index 00000000..69c51fae --- /dev/null +++ b/src/widgets/OverviewWidget.cpp @@ -0,0 +1,33 @@ +#include "MainWindow.h" +#include "OverviewWidget.h" +#include "OverviewView.h" + +OverviewWidget::OverviewWidget(MainWindow *main, QAction *action) : + CutterDockWidget(main, action) +{ + this->setWindowTitle("Graph Overview"); + this->setObjectName("Graph Overview"); + this->setAllowedAreas(Qt::AllDockWidgetAreas); + this->graphView = new OverviewView(this); + this->setWidget(graphView); + refreshDeferrer = createRefreshDeferrer([this]() { + updateContents(); + }); + + connect(this, &QDockWidget::visibilityChanged, this, [ = ](bool visibility) { + if (visibility) { + Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Graph); + updateContents(); + } + }); +} + +OverviewWidget::~OverviewWidget() {} + +void OverviewWidget::updateContents() +{ + if (!refreshDeferrer->attemptRefresh(nullptr)) { + return; + } + graphView->refreshView(); +} diff --git a/src/widgets/OverviewWidget.h b/src/widgets/OverviewWidget.h new file mode 100644 index 00000000..c58c2b01 --- /dev/null +++ b/src/widgets/OverviewWidget.h @@ -0,0 +1,28 @@ +#ifndef OVERVIEWWIDGET_H +#define OVERVIEWWIDGET_H + +#include "CutterDockWidget.h" + +class MainWindow; +class OverviewView; + +class OverviewWidget : public CutterDockWidget +{ + Q_OBJECT + +public: + explicit OverviewWidget(MainWindow *main, QAction *action = nullptr); + ~OverviewWidget(); + OverviewView *graphView; + +private: + RefreshDeferrer *refreshDeferrer; + +private slots: + /** + * @brief update the overview + */ + void updateContents(); +}; + +#endif // OverviewWIDGET_H