mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-18 18:38:51 +00:00
Horizontal graph (#2234)
* Create adapter for converting vertical layout into horizontal * Fix edge spacing override for edges going out of switch statement. * Update documentation.
This commit is contained in:
parent
56c2e3741a
commit
837dd63e6b
@ -41,11 +41,17 @@ When Graphviz is installed, the following options are also available:
|
|||||||
- Graphviz PNG Image
|
- Graphviz PNG Image
|
||||||
- Graphviz JPG Image
|
- Graphviz JPG Image
|
||||||
- Graphviz SVG Image
|
- Graphviz SVG Image
|
||||||
-
|
|
||||||
|
|
||||||
**Steps:** Right click anywhere on the Graph view and choose ``Export Graph``.
|
**Steps:** Right click anywhere on the Graph view and choose ``Export Graph``.
|
||||||
|
|
||||||
|
|
||||||
|
Graph Layout Direction
|
||||||
|
----------------------------------------
|
||||||
|
**Description:** Graph layout direction can be either vertical top to bottom or horizontal left to right.
|
||||||
|
|
||||||
|
|
||||||
|
**Steps:** Right click anywhere on the Graph view ``Layout -> Horizontal``.
|
||||||
|
|
||||||
Choose Graph Layout
|
Choose Graph Layout
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
**Description:** Choose the layout to be used by Cutter to display the Graph. Cutter supports the following Graph layout algorithms:
|
**Description:** Choose the layout to be used by Cutter to display the Graph. Cutter supports the following Graph layout algorithms:
|
||||||
@ -56,10 +62,7 @@ Choose Graph Layout
|
|||||||
|
|
||||||
When Graphviz is installed, the following options are also available:
|
When Graphviz is installed, the following options are also available:
|
||||||
|
|
||||||
- Graphviz polyline
|
- Graphviz polyline
|
||||||
- Graphviz polyline LR
|
- Graphviz ortho
|
||||||
- Graphviz ortho
|
|
||||||
- Graphviz ortho LR
|
|
||||||
|
|
||||||
|
|
||||||
**Steps:** Right click anywhere on the Graph view and choose a layout from the ``Layout`` sub-menu.
|
**Steps:** Right click anywhere on the Graph view and choose a layout from the ``Layout`` sub-menu.
|
@ -424,7 +424,8 @@ SOURCES += \
|
|||||||
common/IOModesController.cpp \
|
common/IOModesController.cpp \
|
||||||
common/SettingsUpgrade.cpp \
|
common/SettingsUpgrade.cpp \
|
||||||
dialogs/LayoutManager.cpp \
|
dialogs/LayoutManager.cpp \
|
||||||
common/CutterLayout.cpp
|
common/CutterLayout.cpp \
|
||||||
|
widgets/GraphHorizontalAdapter.cpp
|
||||||
|
|
||||||
GRAPHVIZ_SOURCES = \
|
GRAPHVIZ_SOURCES = \
|
||||||
widgets/GraphvizLayout.cpp
|
widgets/GraphvizLayout.cpp
|
||||||
@ -577,7 +578,8 @@ HEADERS += \
|
|||||||
dialogs/LayoutManager.h \
|
dialogs/LayoutManager.h \
|
||||||
common/CutterLayout.h \
|
common/CutterLayout.h \
|
||||||
common/BinaryTrees.h \
|
common/BinaryTrees.h \
|
||||||
common/LinkedListPool.h
|
common/LinkedListPool.h \
|
||||||
|
widgets/GraphHorizontalAdapter.h
|
||||||
|
|
||||||
GRAPHVIZ_HEADERS = widgets/GraphvizLayout.h
|
GRAPHVIZ_HEADERS = widgets/GraphvizLayout.h
|
||||||
|
|
||||||
|
@ -42,6 +42,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
|
|||||||
MainWindow *mainWindow, QList<QAction *> additionalMenuActions)
|
MainWindow *mainWindow, QList<QAction *> additionalMenuActions)
|
||||||
: GraphView(parent),
|
: GraphView(parent),
|
||||||
mFontMetrics(nullptr),
|
mFontMetrics(nullptr),
|
||||||
|
graphLayout(GraphView::Layout::GridMedium),
|
||||||
blockMenu(new DisassemblyContextMenu(this, mainWindow)),
|
blockMenu(new DisassemblyContextMenu(this, mainWindow)),
|
||||||
contextMenu(new QMenu(this)),
|
contextMenu(new QMenu(this)),
|
||||||
seekable(seekable),
|
seekable(seekable),
|
||||||
@ -104,27 +105,29 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget *parent, CutterSeekable *se
|
|||||||
, {tr("Grid wide"), GraphView::Layout::GridWide}
|
, {tr("Grid wide"), GraphView::Layout::GridWide}
|
||||||
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
||||||
, {tr("Graphviz polyline"), GraphView::Layout::GraphvizPolyline}
|
, {tr("Graphviz polyline"), GraphView::Layout::GraphvizPolyline}
|
||||||
, {tr("Graphviz polyline LR"), GraphView::Layout::GraphvizPolylineLR}
|
|
||||||
, {tr("Graphviz ortho"), GraphView::Layout::GraphvizOrtho}
|
, {tr("Graphviz ortho"), GraphView::Layout::GraphvizOrtho}
|
||||||
, {tr("Graphviz ortho LR"), GraphView::Layout::GraphvizOrthoLR}
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
auto layoutMenu = contextMenu->addMenu(tr("Layout"));
|
auto layoutMenu = contextMenu->addMenu(tr("Layout"));
|
||||||
|
horizontalLayoutAction = layoutMenu->addAction(tr("Horizontal"));
|
||||||
|
horizontalLayoutAction->setCheckable(true);
|
||||||
|
layoutMenu->addSeparator();
|
||||||
|
connect(horizontalLayoutAction, &QAction::toggled, this, &DisassemblerGraphView::updateLayout);
|
||||||
QActionGroup *layoutGroup = new QActionGroup(layoutMenu);
|
QActionGroup *layoutGroup = new QActionGroup(layoutMenu);
|
||||||
for (auto &item : LAYOUT_CONFIG) {
|
for (auto &item : LAYOUT_CONFIG) {
|
||||||
auto action = layoutGroup->addAction(item.first);
|
auto action = layoutGroup->addAction(item.first);
|
||||||
action->setCheckable(true);
|
action->setCheckable(true);
|
||||||
GraphView::Layout layout = item.second;
|
GraphView::Layout layout = item.second;
|
||||||
connect(action, &QAction::triggered, this, [this, layout]() {
|
connect(action, &QAction::triggered, this, [this, layout]() {
|
||||||
setGraphLayout(layout);
|
this->graphLayout = layout;
|
||||||
refreshView();
|
updateLayout();
|
||||||
onSeekChanged(this->seekable->getOffset()); // try to keep the view on current block
|
|
||||||
});
|
});
|
||||||
if (layout == getGraphLayout()) {
|
if (layout == this->graphLayout) {
|
||||||
action->setChecked(true);
|
action->setChecked(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
layoutMenu->addActions(layoutGroup->actions());
|
layoutMenu->addActions(layoutGroup->actions());
|
||||||
|
|
||||||
contextMenu->addSeparator();
|
contextMenu->addSeparator();
|
||||||
contextMenu->addActions(additionalMenuActions);
|
contextMenu->addActions(additionalMenuActions);
|
||||||
|
|
||||||
@ -1155,6 +1158,13 @@ void DisassemblerGraphView::onActionUnhighlightBITriggered()
|
|||||||
Config()->colorsUpdated();
|
Config()->colorsUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisassemblerGraphView::updateLayout()
|
||||||
|
{
|
||||||
|
setGraphLayout(GraphView::makeGraphLayout(graphLayout, horizontalLayoutAction->isChecked()));
|
||||||
|
refreshView();
|
||||||
|
onSeekChanged(this->seekable->getOffset()); // try to keep the view on current block
|
||||||
|
}
|
||||||
|
|
||||||
void DisassemblerGraphView::exportGraph(QString filePath, GraphExportType type)
|
void DisassemblerGraphView::exportGraph(QString filePath, GraphExportType type)
|
||||||
{
|
{
|
||||||
bool graphTransparent = Config()->getBitmapTransparentState();
|
bool graphTransparent = Config()->getBitmapTransparentState();
|
||||||
|
@ -159,6 +159,7 @@ private slots:
|
|||||||
void on_actionExportGraph_triggered();
|
void on_actionExportGraph_triggered();
|
||||||
void onActionHighlightBITriggered();
|
void onActionHighlightBITriggered();
|
||||||
void onActionUnhighlightBITriggered();
|
void onActionUnhighlightBITriggered();
|
||||||
|
void updateLayout();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool transition_dont_seek = false;
|
bool transition_dont_seek = false;
|
||||||
@ -173,8 +174,11 @@ private:
|
|||||||
bool emptyGraph;
|
bool emptyGraph;
|
||||||
ut64 currentBlockAddress = RVA_INVALID;
|
ut64 currentBlockAddress = RVA_INVALID;
|
||||||
|
|
||||||
|
GraphView::Layout graphLayout;
|
||||||
|
|
||||||
DisassemblyContextMenu *blockMenu;
|
DisassemblyContextMenu *blockMenu;
|
||||||
QMenu *contextMenu;
|
QMenu *contextMenu;
|
||||||
|
QAction* horizontalLayoutAction;
|
||||||
|
|
||||||
void connectSeekChanged(bool disconnect);
|
void connectSeekChanged(bool disconnect);
|
||||||
|
|
||||||
|
@ -248,7 +248,7 @@ void GraphGridLayout::CalculateLayout(std::unordered_map<ut64, GraphBlock> &bloc
|
|||||||
}
|
}
|
||||||
for (const auto &edgeList : layoutState.edge) {
|
for (const auto &edgeList : layoutState.edge) {
|
||||||
auto &startBlock = layoutState.grid_blocks[edgeList.first];
|
auto &startBlock = layoutState.grid_blocks[edgeList.first];
|
||||||
startBlock.outputCount++;
|
startBlock.outputCount = edgeList.second.size();
|
||||||
for (auto &edge : edgeList.second) {
|
for (auto &edge : edgeList.second) {
|
||||||
auto &targetBlock = layoutState.grid_blocks[edge.dest];
|
auto &targetBlock = layoutState.grid_blocks[edge.dest];
|
||||||
targetBlock.inputCount++;
|
targetBlock.inputCount++;
|
||||||
@ -573,6 +573,9 @@ void GraphGridLayout::calculateEdgeMainColumn(GraphGridLayout::LayoutState &stat
|
|||||||
void GraphGridLayout::roughRouting(GraphGridLayout::LayoutState &state) const
|
void GraphGridLayout::roughRouting(GraphGridLayout::LayoutState &state) const
|
||||||
{
|
{
|
||||||
auto getSpacingOverride = [this](int blockWidth, int edgeCount) {
|
auto getSpacingOverride = [this](int blockWidth, int edgeCount) {
|
||||||
|
if (edgeCount == 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
int maxSpacing = blockWidth / edgeCount;
|
int maxSpacing = blockWidth / edgeCount;
|
||||||
if (maxSpacing < layoutConfig.edgeHorizontalSpacing) {
|
if (maxSpacing < layoutConfig.edgeHorizontalSpacing) {
|
||||||
return std::max(maxSpacing, 1);
|
return std::max(maxSpacing, 1);
|
||||||
@ -614,6 +617,13 @@ void GraphGridLayout::roughRouting(GraphGridLayout::LayoutState &state) const
|
|||||||
target.inputCount);
|
target.inputCount);
|
||||||
edge.points.front().spacingOverride = startSpacingOverride;
|
edge.points.front().spacingOverride = startSpacingOverride;
|
||||||
edge.points.back().spacingOverride = targetSpacingOverride;
|
edge.points.back().spacingOverride = targetSpacingOverride;
|
||||||
|
if (edge.points.size() <= 2) {
|
||||||
|
if (startSpacingOverride && startSpacingOverride < targetSpacingOverride) {
|
||||||
|
edge.points.back().spacingOverride = startSpacingOverride;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
edge.points[1].spacingOverride = startSpacingOverride;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int length = 0;
|
int length = 0;
|
||||||
|
58
src/widgets/GraphHorizontalAdapter.cpp
Normal file
58
src/widgets/GraphHorizontalAdapter.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "GraphHorizontalAdapter.h"
|
||||||
|
|
||||||
|
GraphHorizontalAdapter::GraphHorizontalAdapter(std::unique_ptr<GraphLayout> layout)
|
||||||
|
: GraphLayout({})
|
||||||
|
, layout(std::move(layout))
|
||||||
|
{
|
||||||
|
swapLayoutConfigDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphHorizontalAdapter::CalculateLayout(
|
||||||
|
GraphLayout::Graph &blocks,
|
||||||
|
unsigned long long entry,
|
||||||
|
int &width,
|
||||||
|
int &height) const
|
||||||
|
{
|
||||||
|
for (auto &block : blocks) {
|
||||||
|
std::swap(block.second.width, block.second.height);
|
||||||
|
}
|
||||||
|
layout->CalculateLayout(blocks, entry, height, width); // intentionally swapping height and width
|
||||||
|
for (auto &block : blocks) {
|
||||||
|
std::swap(block.second.width, block.second.height);
|
||||||
|
std::swap(block.second.x, block.second.y);
|
||||||
|
for (auto &edge : block.second.edges) {
|
||||||
|
for (auto &point : edge.polyline) {
|
||||||
|
std::swap(point.rx(), point.ry());
|
||||||
|
}
|
||||||
|
switch (edge.arrow) {
|
||||||
|
case GraphEdge::Down:
|
||||||
|
edge.arrow = GraphEdge::Right;
|
||||||
|
break;
|
||||||
|
case GraphEdge::Left:
|
||||||
|
edge.arrow = GraphEdge::Up;
|
||||||
|
break;
|
||||||
|
case GraphEdge::Up:
|
||||||
|
edge.arrow = GraphEdge::Left;
|
||||||
|
break;
|
||||||
|
case GraphEdge::Right:
|
||||||
|
edge.arrow = GraphEdge::Down;
|
||||||
|
break;
|
||||||
|
case GraphEdge::None:
|
||||||
|
edge.arrow = GraphEdge::None;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphHorizontalAdapter::setLayoutConfig(const GraphLayout::LayoutConfig &config)
|
||||||
|
{
|
||||||
|
GraphLayout::setLayoutConfig(config);
|
||||||
|
swapLayoutConfigDirection();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GraphHorizontalAdapter::swapLayoutConfigDirection()
|
||||||
|
{
|
||||||
|
std::swap(layoutConfig.edgeVerticalSpacing, layoutConfig.edgeHorizontalSpacing);
|
||||||
|
std::swap(layoutConfig.blockVerticalSpacing, layoutConfig.blockHorizontalSpacing);
|
||||||
|
}
|
24
src/widgets/GraphHorizontalAdapter.h
Normal file
24
src/widgets/GraphHorizontalAdapter.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#ifndef GRAPH_HORIZONTAL_ADAPTER_H
|
||||||
|
#define GRAPH_HORIZONTAL_ADAPTER_H
|
||||||
|
|
||||||
|
#include "core/Cutter.h"
|
||||||
|
#include "GraphLayout.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adapter for converting vertical graph layout into horizontal one.
|
||||||
|
*/
|
||||||
|
class GraphHorizontalAdapter : public GraphLayout
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
GraphHorizontalAdapter(std::unique_ptr<GraphLayout> layout);
|
||||||
|
virtual void CalculateLayout(GraphLayout::Graph &blocks,
|
||||||
|
ut64 entry,
|
||||||
|
int &width,
|
||||||
|
int &height) const override;
|
||||||
|
void setLayoutConfig(const LayoutConfig &config) override;
|
||||||
|
private:
|
||||||
|
std::unique_ptr<GraphLayout> layout;
|
||||||
|
void swapLayoutConfigDirection();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // GRAPH_HORIZONTAL_ADAPTER_H
|
@ -42,6 +42,10 @@ public:
|
|||||||
virtual ~GraphLayout() {}
|
virtual ~GraphLayout() {}
|
||||||
virtual void CalculateLayout(Graph &blocks, ut64 entry, int &width,
|
virtual void CalculateLayout(Graph &blocks, ut64 entry, int &width,
|
||||||
int &height) const = 0;
|
int &height) const = 0;
|
||||||
|
virtual void setLayoutConfig(const LayoutConfig &config)
|
||||||
|
{
|
||||||
|
this->layoutConfig = config;
|
||||||
|
};
|
||||||
protected:
|
protected:
|
||||||
LayoutConfig layoutConfig;
|
LayoutConfig layoutConfig;
|
||||||
};
|
};
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
||||||
#include "GraphvizLayout.h"
|
#include "GraphvizLayout.h"
|
||||||
#endif
|
#endif
|
||||||
|
#include "GraphHorizontalAdapter.h"
|
||||||
#include "Helpers.h"
|
#include "Helpers.h"
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@ -36,7 +37,7 @@ GraphView::GraphView(QWidget *parent)
|
|||||||
glWidget = nullptr;
|
glWidget = nullptr;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
setGraphLayout(Layout::GridMedium);
|
setGraphLayout(makeGraphLayout(Layout::GridMedium));
|
||||||
}
|
}
|
||||||
|
|
||||||
GraphView::~GraphView()
|
GraphView::~GraphView()
|
||||||
@ -513,36 +514,45 @@ QPoint GraphView::viewToLogicalCoordinates(QPoint p)
|
|||||||
return p / current_scale + offset;
|
return p / current_scale + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphView::setGraphLayout(GraphView::Layout layout)
|
void GraphView::setGraphLayout(std::unique_ptr<GraphLayout> layout)
|
||||||
{
|
{
|
||||||
graphLayout = layout;
|
graphLayoutSystem = std::move(layout);
|
||||||
|
if (!graphLayoutSystem) {
|
||||||
|
graphLayoutSystem = makeGraphLayout(Layout::GridMedium);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<GraphLayout> GraphView::makeGraphLayout(GraphView::Layout layout, bool horizontal)
|
||||||
|
{
|
||||||
|
std::unique_ptr<GraphLayout> result;
|
||||||
|
bool needAdapter = true;
|
||||||
switch (layout) {
|
switch (layout) {
|
||||||
case Layout::GridNarrow:
|
case Layout::GridNarrow:
|
||||||
this->graphLayoutSystem.reset(new GraphGridLayout(GraphGridLayout::LayoutType::Narrow));
|
result.reset(new GraphGridLayout(GraphGridLayout::LayoutType::Narrow));
|
||||||
break;
|
break;
|
||||||
case Layout::GridMedium:
|
case Layout::GridMedium:
|
||||||
this->graphLayoutSystem.reset(new GraphGridLayout(GraphGridLayout::LayoutType::Medium));
|
result.reset(new GraphGridLayout(GraphGridLayout::LayoutType::Medium));
|
||||||
break;
|
break;
|
||||||
case Layout::GridWide:
|
case Layout::GridWide:
|
||||||
this->graphLayoutSystem.reset(new GraphGridLayout(GraphGridLayout::LayoutType::Wide));
|
result.reset(new GraphGridLayout(GraphGridLayout::LayoutType::Wide));
|
||||||
break;
|
break;
|
||||||
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
||||||
case Layout::GraphvizOrtho:
|
case Layout::GraphvizOrtho:
|
||||||
this->graphLayoutSystem.reset(new GraphvizLayout(GraphvizLayout::LineType::Ortho));
|
result.reset(new GraphvizLayout(GraphvizLayout::LineType::Ortho,
|
||||||
break;
|
horizontal ? GraphvizLayout::Direction::LR : GraphvizLayout::Direction::TB));
|
||||||
case Layout::GraphvizOrthoLR:
|
needAdapter = false;
|
||||||
this->graphLayoutSystem.reset(new GraphvizLayout(GraphvizLayout::LineType::Ortho,
|
|
||||||
GraphvizLayout::Direction::LR));
|
|
||||||
break;
|
break;
|
||||||
case Layout::GraphvizPolyline:
|
case Layout::GraphvizPolyline:
|
||||||
this->graphLayoutSystem.reset(new GraphvizLayout(GraphvizLayout::LineType::Polyline));
|
result.reset(new GraphvizLayout(GraphvizLayout::LineType::Polyline,
|
||||||
break;
|
horizontal ? GraphvizLayout::Direction::LR : GraphvizLayout::Direction::TB));
|
||||||
case Layout::GraphvizPolylineLR:
|
needAdapter = false;
|
||||||
this->graphLayoutSystem.reset(new GraphvizLayout(GraphvizLayout::LineType::Polyline,
|
|
||||||
GraphvizLayout::Direction::LR));
|
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (needAdapter && horizontal) {
|
||||||
|
result.reset(new GraphHorizontalAdapter(std::move(result)));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphView::addBlock(GraphView::GraphBlock block)
|
void GraphView::addBlock(GraphView::GraphBlock block)
|
||||||
|
@ -44,11 +44,10 @@ public:
|
|||||||
, GridWide
|
, GridWide
|
||||||
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
#ifdef CUTTER_ENABLE_GRAPHVIZ
|
||||||
, GraphvizOrtho
|
, GraphvizOrtho
|
||||||
, GraphvizOrthoLR
|
|
||||||
, GraphvizPolyline
|
, GraphvizPolyline
|
||||||
, GraphvizPolylineLR
|
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
static std::unique_ptr<GraphLayout> makeGraphLayout(Layout layout, bool horizontal = false);
|
||||||
|
|
||||||
struct EdgeConfiguration {
|
struct EdgeConfiguration {
|
||||||
QColor color = QColor(128, 128, 128);
|
QColor color = QColor(128, 128, 128);
|
||||||
@ -77,8 +76,8 @@ public:
|
|||||||
GraphView::GraphBlock *getBlockContaining(QPoint p);
|
GraphView::GraphBlock *getBlockContaining(QPoint p);
|
||||||
QPoint viewToLogicalCoordinates(QPoint p);
|
QPoint viewToLogicalCoordinates(QPoint p);
|
||||||
|
|
||||||
void setGraphLayout(Layout layout);
|
void setGraphLayout(std::unique_ptr<GraphLayout> layout);
|
||||||
Layout getGraphLayout() const { return graphLayout; }
|
GraphLayout& getGraphLayout() const { return *graphLayoutSystem; }
|
||||||
|
|
||||||
void paint(QPainter &p, QPoint offset, QRect area, qreal scale = 1.0, bool interactive = true);
|
void paint(QPainter &p, QPoint offset, QRect area, qreal scale = 1.0, bool interactive = true);
|
||||||
|
|
||||||
@ -174,7 +173,6 @@ private:
|
|||||||
QSize cacheSize;
|
QSize cacheSize;
|
||||||
QOpenGLWidget *glWidget;
|
QOpenGLWidget *glWidget;
|
||||||
#endif
|
#endif
|
||||||
Layout graphLayout;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief flag to control if the cache is invalid and should be re-created in the next draw
|
* @brief flag to control if the cache is invalid and should be re-created in the next draw
|
||||||
|
Loading…
Reference in New Issue
Block a user