parent
1e9bf1ab7c
commit
edbaedb47b
|
|
@ -542,6 +542,7 @@ void AppearanceDialog::colorInfoListInit()
|
|||
colorInfoListAppend(tr("Graph:"), "", "");
|
||||
colorInfoListAppend(tr("Background"), "GraphBackgroundColor", "");
|
||||
colorInfoListAppend(tr("Node"), "GraphNodeColor", "GraphNodeBackgroundColor");
|
||||
colorInfoListAppend(tr("Current node shadow"), "GraphCurrentShadowColor", "");
|
||||
colorInfoListAppend(tr("Terminal node shadow"), "GraphRetShadowColor", "");
|
||||
colorInfoListAppend(tr("Indirect call shadow"), "GraphIndirectcallShadowColor", "");
|
||||
colorInfoListAppend(tr("Unconditional branch line"), "GraphJmpColor", "");
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
|||
//Start disassembly view at the entry point of the binary
|
||||
this->function = 0;
|
||||
this->ready = false;
|
||||
this->viewportReady = false;
|
||||
this->desired_pos = nullptr;
|
||||
this->highlight_token = nullptr;
|
||||
this->cur_instr = 0;
|
||||
|
|
@ -47,6 +48,21 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
|||
this->blocks.clear();
|
||||
this->saveGraph = false;
|
||||
|
||||
//Initialize zoom values
|
||||
this->graphZoomMode = ConfigBool("Gui", "GraphZoomMode");
|
||||
this->zoomLevel = 1;
|
||||
this->zoomLevelOld = 1;
|
||||
this->zoomStep = 0.1;
|
||||
this->zoomOverviewValue = 0.5; //text is hidden
|
||||
this->zoomMaximum = 1;
|
||||
|
||||
//zoomScrollThreshold (relative to viewport size) adds fixed free space around the graph in order to make it free to move/scale
|
||||
//0.9 makes at least 10% of the graph allways visible regardless of scroll value
|
||||
//0.5 - at least half of the graph
|
||||
//0 - no margins ()
|
||||
//this->zoomScrollThreshold = 1; // default now
|
||||
//TODO: implement ^^^
|
||||
|
||||
this->initFont();
|
||||
|
||||
//Initialize scroll bars
|
||||
|
|
@ -56,8 +72,9 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
|||
this->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
this->horizontalScrollBar()->setSingleStep(this->charWidth);
|
||||
this->verticalScrollBar()->setSingleStep(this->charHeight);
|
||||
QSize areaSize = this->viewport()->size();
|
||||
this->adjustSize(areaSize.width(), areaSize.height());
|
||||
|
||||
//QSize areaSize = this->viewport()->size(); <-\
|
||||
//this->adjustSize(areaSize.width(), areaSize.height()); <-- useless at this point (?)
|
||||
|
||||
//Setup context menu
|
||||
setupContextMenu();
|
||||
|
|
@ -76,7 +93,7 @@ DisassemblerGraphView::DisassemblerGraphView(QWidget* parent)
|
|||
connect(Config(), SIGNAL(shortcutsUpdated()), this, SLOT(shortcutsUpdatedSlot()));
|
||||
connect(Config(), SIGNAL(tokenizerConfigUpdated()), this, SLOT(tokenizerConfigUpdatedSlot()));
|
||||
|
||||
colorsUpdatedSlot();
|
||||
//colorsUpdatedSlot(); <-- already called somewhere
|
||||
}
|
||||
|
||||
DisassemblerGraphView::~DisassemblerGraphView()
|
||||
|
|
@ -97,28 +114,99 @@ void DisassemblerGraphView::initFont()
|
|||
mFontMetrics = new CachedFontMetrics(this, font());
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::adjustSize(int width, int height)
|
||||
void DisassemblerGraphView::adjustSize(int viewportWidth, int viewportHeight, QPoint mousePosition, bool fitToWindow)
|
||||
{
|
||||
//Recompute size information
|
||||
this->renderWidth = this->width;
|
||||
this->renderHeight = this->height;
|
||||
this->renderXOfs = 0;
|
||||
this->renderYOfs = 0;
|
||||
if(this->renderWidth < width)
|
||||
//bugfix - resize event (during several initial calls) may reset correct adjustment already made
|
||||
if(viewportHeight < 30)
|
||||
return;
|
||||
|
||||
//When zoom mode is enabled, graph turns to a free scallable object with ability to zoom in/out on any point (like IDA)
|
||||
if(graphZoomMode)
|
||||
{
|
||||
this->renderXOfs = (width - this->renderWidth) / 2;
|
||||
this->renderWidth = width;
|
||||
qreal graphWidth = this->width;
|
||||
qreal graphHeight = this->height;
|
||||
int hScrollRange;
|
||||
int vScrollRange;
|
||||
|
||||
renderWidth = graphWidth * zoomLevel;
|
||||
renderHeight = graphHeight * zoomLevel;
|
||||
renderXOfs = viewportWidth;
|
||||
renderYOfs = viewportHeight;
|
||||
|
||||
//Adjust scroll bar range
|
||||
hScrollRange = renderWidth + viewportWidth;
|
||||
vScrollRange = renderHeight + viewportHeight;
|
||||
|
||||
QPointF deltaMouseReal;
|
||||
QPointF deltaMouseDiff;
|
||||
|
||||
//Addition to scrool position depending on viewport offset
|
||||
qreal zoomStepReal; //real step which may differ from default step
|
||||
if(zoomDirection > 0)
|
||||
{
|
||||
zoomStepReal = (zoomLevel - zoomLevelOld) / zoomLevel;
|
||||
zoomStepReal /= (1 - zoomStepReal);
|
||||
}
|
||||
else
|
||||
{
|
||||
zoomStepReal = (zoomLevelOld - zoomLevel) / zoomLevelOld;
|
||||
}
|
||||
qreal deltaXOfs = renderXOfs * zoomStepReal * zoomDirection;
|
||||
qreal deltaYOfs = renderYOfs * zoomStepReal * zoomDirection;
|
||||
|
||||
|
||||
QPoint scrollPositionOld = QPoint(horizontalScrollBar()->value(), verticalScrollBar()->value());
|
||||
|
||||
horizontalScrollBar()->setPageStep(viewportWidth);
|
||||
horizontalScrollBar()->setRange(0, hScrollRange);
|
||||
verticalScrollBar()->setPageStep(viewportHeight);
|
||||
verticalScrollBar()->setRange(0, vScrollRange);
|
||||
|
||||
if(!mousePosition.isNull()) //Adjust to cursor position
|
||||
{
|
||||
deltaMouseReal = mousePosition / zoomLevelOld + scrollPositionOld / zoomLevelOld;
|
||||
deltaMouseDiff = deltaMouseReal * zoomLevel - deltaMouseReal * zoomLevelOld;
|
||||
|
||||
horizontalScrollBar()->setValue(qRound(scrollPositionOld.x() + deltaMouseDiff.x() - deltaXOfs));
|
||||
verticalScrollBar()->setValue(qRound(scrollPositionOld.y() + deltaMouseDiff.y() - deltaYOfs));
|
||||
}
|
||||
else if(fitToWindow) //Fit to window or 50/50
|
||||
{
|
||||
horizontalScrollBar()->setValue(hScrollRange / 2);
|
||||
verticalScrollBar()->setValue(vScrollRange / 2);
|
||||
}
|
||||
}
|
||||
if(this->renderHeight < height)
|
||||
else //zoom mode is disabled
|
||||
{
|
||||
this->renderYOfs = (height - this->renderHeight) / 2;
|
||||
this->renderHeight = height;
|
||||
this->renderWidth = this->width;
|
||||
this->renderHeight = this->height;
|
||||
this->renderXOfs = 0;
|
||||
this->renderYOfs = 0;
|
||||
if(this->renderWidth < viewportWidth)
|
||||
{
|
||||
this->renderXOfs = (viewportWidth - this->renderWidth) / 2;
|
||||
this->renderWidth = viewportWidth;
|
||||
}
|
||||
if(this->renderHeight < viewportHeight)
|
||||
{
|
||||
this->renderYOfs = (viewportHeight - this->renderHeight) / 2;
|
||||
this->renderHeight = viewportHeight;
|
||||
}
|
||||
//Update scroll bar information
|
||||
this->horizontalScrollBar()->setPageStep(viewportWidth);
|
||||
this->horizontalScrollBar()->setRange(0, this->renderWidth - viewportWidth);
|
||||
this->verticalScrollBar()->setPageStep(viewportHeight);
|
||||
this->verticalScrollBar()->setRange(0, this->renderHeight - viewportHeight);
|
||||
}
|
||||
//Update scroll bar information
|
||||
this->horizontalScrollBar()->setPageStep(width);
|
||||
this->horizontalScrollBar()->setRange(0, this->renderWidth - width);
|
||||
this->verticalScrollBar()->setPageStep(height);
|
||||
this->verticalScrollBar()->setRange(0, this->renderHeight - height);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::showEvent(QShowEvent* event)
|
||||
{
|
||||
//before graph tab is shown for the first time the viewport has uninitialized width and height
|
||||
if(!this->viewportReady)
|
||||
this->viewportReady = true;
|
||||
|
||||
event->ignore();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::resizeEvent(QResizeEvent* event)
|
||||
|
|
@ -160,6 +248,47 @@ void DisassemblerGraphView::copy_address()
|
|||
clipboard->setMimeData(&mime);
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::zoomIn(QPoint mousePosition)
|
||||
{
|
||||
zoomLevelOld = zoomLevel;
|
||||
|
||||
if(zoomLevel == zoomMaximum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//unlike addition, multiplication (by 1/x, x<1) makes zooming more smooth
|
||||
zoomLevel /= (1 - zoomStep * zoomBoost);
|
||||
|
||||
if(zoomLevel > zoomMaximum)
|
||||
{
|
||||
zoomLevel = zoomMaximum;
|
||||
}
|
||||
auto areaSize = viewport()->size();
|
||||
adjustSize(areaSize.width(), areaSize.height(), mousePosition);
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::zoomOut(QPoint mousePosition)
|
||||
{
|
||||
zoomLevelOld = zoomLevel;
|
||||
|
||||
if(zoomLevel == zoomMinimum)
|
||||
{
|
||||
return;
|
||||
}
|
||||
//unlike subtraction, multiplication makes zooming more smooth
|
||||
zoomLevel *= (1 - zoomStep * zoomBoost);
|
||||
|
||||
if(zoomLevel < zoomMinimum)
|
||||
{
|
||||
zoomLevel = zoomMinimum;
|
||||
}
|
||||
|
||||
auto areaSize = viewport()->size();
|
||||
adjustSize(areaSize.width(), areaSize.height(), mousePosition);
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::paintNormal(QPainter & p, QRect & viewportRect, int xofs, int yofs)
|
||||
{
|
||||
//Translate the painter
|
||||
|
|
@ -423,6 +552,224 @@ void DisassemblerGraphView::paintOverview(QPainter & p, QRect & viewportRect, in
|
|||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::paintZoom(QPainter & p, QRect & viewportRect, int xofs, int yofs)
|
||||
{
|
||||
//Based on paintNormal and paintOverview (depending on zoom level)
|
||||
|
||||
auto dbgfunctions = DbgFunctions();
|
||||
|
||||
QPoint translation(this->renderXOfs - xofs, this->renderYOfs - yofs);
|
||||
p.translate(translation);\
|
||||
p.scale(zoomLevel, zoomLevel);
|
||||
|
||||
//Adjust imaginary viewport rect at new zoom level
|
||||
viewportRect.setWidth(viewportRect.width() / zoomLevel);
|
||||
viewportRect.setHeight(viewportRect.height() / zoomLevel);
|
||||
viewportRect.translate(-translation.x() / zoomLevel, -translation.y() / zoomLevel);
|
||||
|
||||
//Current block
|
||||
duint cipBlock = 0;
|
||||
auto found = currentBlockMap.find(mCip);
|
||||
if(found != currentBlockMap.end())
|
||||
cipBlock = found->second;
|
||||
|
||||
//Scaled pen
|
||||
QPen pen;
|
||||
qreal penWidth = 1 / zoomLevel;
|
||||
pen.setColor(graphNodeColor);
|
||||
pen.setWidthF(penWidth);
|
||||
|
||||
//Render each node
|
||||
for(auto & blockIt : this->blocks)
|
||||
{
|
||||
DisassemblerBlock & block = blockIt.second;
|
||||
|
||||
bool blockSelected = false;
|
||||
for(const Instr & instr : block.block.instrs)
|
||||
{
|
||||
if(instr.addr == this->cur_instr)
|
||||
{
|
||||
blockSelected = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Ignore blocks that are not in view
|
||||
if(viewportRect.intersects(QRect(block.x + this->charWidth, block.y + this->charWidth,
|
||||
block.width - (2 * this->charWidth), block.height - (2 * this->charWidth))))
|
||||
{
|
||||
//Get block metadata
|
||||
auto isCip = block.block.entry == cipBlock;
|
||||
auto traceCount = dbgfunctions->GetTraceRecordHitCount(block.block.entry);
|
||||
|
||||
if(zoomLevel > zoomOverviewValue) //Normal mode
|
||||
{
|
||||
//Render shadow
|
||||
p.setPen(QColor(0, 0, 0, 0));
|
||||
if(isCip)
|
||||
p.setBrush(graphCurrentShadowColor);
|
||||
else if(block.block.terminal)
|
||||
p.setBrush(retShadowColor);
|
||||
else if(block.block.indirectcall)
|
||||
p.setBrush(indirectcallShadowColor);
|
||||
else
|
||||
p.setBrush(QColor(0, 0, 0, 100));
|
||||
p.drawRect(block.x + this->charWidth + 4, block.y + this->charWidth + 4,
|
||||
block.width - (4 + 2 * this->charWidth), block.height - (4 + 2 * this->charWidth));
|
||||
|
||||
//Node background
|
||||
pen.setColor(graphNodeColor);
|
||||
p.setPen(pen);
|
||||
p.setBrush(graphNodeBackgroundColor);
|
||||
p.drawRect(block.x + this->charWidth, block.y + this->charWidth,
|
||||
block.width - (4 + 2 * this->charWidth), block.height - (4 + 2 * this->charWidth));
|
||||
|
||||
//Print current instruction background
|
||||
if(this->cur_instr != 0)
|
||||
{
|
||||
int y = block.y + (2 * this->charWidth) + (int(block.block.header_text.lines.size()) * this->charHeight);
|
||||
for(Instr & instr : block.block.instrs)
|
||||
{
|
||||
if(y > viewportRect.y() - int(instr.text.lines.size()) * this->charHeight && y < viewportRect.bottom())
|
||||
{
|
||||
auto selected = instr.addr == this->cur_instr;
|
||||
auto traceCount = dbgfunctions->GetTraceRecordHitCount(instr.addr);
|
||||
|
||||
if(selected && traceCount)
|
||||
{
|
||||
p.fillRect(QRect(block.x + this->charWidth + 3, y, block.width - (10 + 2 * this->charWidth),
|
||||
int(instr.text.lines.size()) * this->charHeight), disassemblyTracedSelectionColor);
|
||||
}
|
||||
else if(selected)
|
||||
{
|
||||
p.fillRect(QRect(block.x + this->charWidth + 3, y, block.width - (10 + 2 * this->charWidth),
|
||||
int(instr.text.lines.size()) * this->charHeight), disassemblySelectionColor);
|
||||
}
|
||||
else if(traceCount)
|
||||
{
|
||||
// Color depending on how often a sequence of code is executed
|
||||
int exponent = 1;
|
||||
while(traceCount >>= 1) //log2(traceCount)
|
||||
exponent++;
|
||||
int colorDiff = (exponent * exponent) / 2;
|
||||
|
||||
// If the user has a light trace background color, substract
|
||||
if(disassemblyTracedColor.blue() > 160)
|
||||
colorDiff *= -1;
|
||||
|
||||
p.fillRect(QRect(block.x + this->charWidth + 3, y, block.width - (10 + 2 * this->charWidth), int(instr.text.lines.size()) * this->charHeight),
|
||||
QColor(disassemblyTracedColor.red(),
|
||||
disassemblyTracedColor.green(),
|
||||
std::max(0, std::min(256, disassemblyTracedColor.blue() + colorDiff))));
|
||||
}
|
||||
}
|
||||
y += int(instr.text.lines.size()) * this->charHeight;
|
||||
}
|
||||
}
|
||||
|
||||
//Render node text
|
||||
auto x = block.x + (2 * this->charWidth);
|
||||
auto y = block.y + (2 * this->charWidth);
|
||||
for(auto & line : block.block.header_text.lines)
|
||||
{
|
||||
if(y > viewportRect.y() - this->charHeight && y < viewportRect.bottom())
|
||||
{
|
||||
RichTextPainter::paintRichText(&p, x, y, block.width, this->charHeight, 0, line, mFontMetrics);
|
||||
}
|
||||
y += this->charHeight;
|
||||
}
|
||||
|
||||
for(Instr & instr : block.block.instrs)
|
||||
{
|
||||
for(auto & line : instr.text.lines)
|
||||
{
|
||||
if(y > viewportRect.y() - this->charHeight && y < viewportRect.bottom())
|
||||
{
|
||||
int rectSize = qRound(this->charWidth);
|
||||
if(rectSize % 2)
|
||||
rectSize++;
|
||||
|
||||
// Assume charWidth <= charHeight
|
||||
QRectF bpRect(x - rectSize / 3.0, y + (this->charHeight - rectSize) / 2.0, rectSize, rectSize);
|
||||
|
||||
bool isbp = DbgGetBpxTypeAt(instr.addr) != bp_none;
|
||||
bool isbpdisabled = DbgIsBpDisabled(instr.addr);
|
||||
bool iscip = instr.addr == mCip;
|
||||
|
||||
if(isbp || isbpdisabled)
|
||||
{
|
||||
if(iscip)
|
||||
{
|
||||
// Left half is cip
|
||||
bpRect.setWidth(bpRect.width() / 2);
|
||||
p.fillRect(bpRect, mCipColor);
|
||||
|
||||
// Right half is breakpoint
|
||||
bpRect.translate(bpRect.width(), 0);
|
||||
}
|
||||
|
||||
p.fillRect(bpRect, isbp ? mBreakpointColor : mDisabledBreakpointColor);
|
||||
}
|
||||
else if(iscip)
|
||||
p.fillRect(bpRect, mCipColor);
|
||||
|
||||
RichTextPainter::paintRichText(&p, x + this->charWidth, y, block.width - this->charWidth, this->charHeight, 0, line, mFontMetrics);
|
||||
}
|
||||
y += this->charHeight;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else //Overview mode
|
||||
{
|
||||
pen.setColor(graphNodeColor);
|
||||
p.setPen(pen);
|
||||
if(isCip)
|
||||
p.setBrush(graphCurrentShadowColor);
|
||||
else if(traceCount)
|
||||
{
|
||||
// Color depending on how often a sequence of code is executed
|
||||
int exponent = 1;
|
||||
while(traceCount >>= 1) //log2(traceCount)
|
||||
exponent++;
|
||||
int colorDiff = (exponent * exponent) / 2;
|
||||
|
||||
// If the user has a light trace background color, substract
|
||||
if(disassemblyTracedColor.blue() > 160)
|
||||
colorDiff *= -1;
|
||||
|
||||
p.setBrush(QColor(disassemblyTracedColor.red(),
|
||||
disassemblyTracedColor.green(),
|
||||
std::max(0, std::min(256, disassemblyTracedColor.blue() + colorDiff))));
|
||||
}
|
||||
else if(block.block.terminal)
|
||||
p.setBrush(retShadowColor);
|
||||
else if(block.block.indirectcall)
|
||||
p.setBrush(indirectcallShadowColor);
|
||||
else
|
||||
p.setBrush(graphNodeBackgroundColor);
|
||||
p.drawRect(block.x + this->charWidth, block.y + this->charWidth,
|
||||
block.width - (4 + 2 * this->charWidth), block.height - (4 + 2 * this->charWidth));
|
||||
}
|
||||
}
|
||||
// Render edges
|
||||
for(DisassemblerEdge & edge : block.edges)
|
||||
{
|
||||
pen.setWidthF(penWidth);
|
||||
pen.setColor(edge.color);
|
||||
p.setPen(pen);
|
||||
|
||||
if(blockSelected)
|
||||
pen.setStyle(Qt::DashLine);
|
||||
p.setPen(pen);
|
||||
p.setBrush(edge.color);
|
||||
p.drawPolyline(edge.polyline);
|
||||
pen.setStyle(Qt::SolidLine);
|
||||
p.setPen(pen);
|
||||
p.drawConvexPolygon(edge.arrow);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::paintEvent(QPaintEvent* event)
|
||||
{
|
||||
Q_UNUSED(event);
|
||||
|
|
@ -445,20 +792,38 @@ void DisassemblerGraphView::paintEvent(QPaintEvent* event)
|
|||
return;
|
||||
}
|
||||
|
||||
if(drawOverview)
|
||||
paintOverview(p, viewportRect, xofs, yofs);
|
||||
if(!graphZoomMode)
|
||||
{
|
||||
if(drawOverview)
|
||||
paintOverview(p, viewportRect, xofs, yofs);
|
||||
else
|
||||
paintNormal(p, viewportRect, xofs, yofs);
|
||||
}
|
||||
else
|
||||
paintNormal(p, viewportRect, xofs, yofs);
|
||||
{
|
||||
paintZoom(p, viewportRect, xofs, yofs);
|
||||
}
|
||||
|
||||
if(saveGraph)
|
||||
{
|
||||
//TODO: speed up large graph saving or show gif loader so it won't look like it has crashed
|
||||
|
||||
//Image corresponds to the current zoom level
|
||||
saveGraph = false;
|
||||
QString path = QFileDialog::getSaveFileName(this, tr("Save as image"), "", tr("PNG file (*.png);;BMP file (*.bmp)"));
|
||||
if(path.isEmpty())
|
||||
return;
|
||||
|
||||
QSize size = this->viewport()->size();
|
||||
QPoint scrollbarPos = QPoint(this->horizontalScrollBar()->value(), this->verticalScrollBar()->value());
|
||||
|
||||
// expand to full render Rectangle
|
||||
this->viewport()->resize(this->renderWidth, this->renderHeight);//OK
|
||||
this->viewport()->resize(this->renderWidth, this->renderHeight);
|
||||
|
||||
if(graphZoomMode)
|
||||
{
|
||||
adjustSize(this->renderWidth, this->renderHeight, QPoint(), true); //set scrollbars to 50%
|
||||
}
|
||||
|
||||
//save viewport to image
|
||||
QRect completeRenderRect = QRect(0, 0, this->renderWidth, this->renderHeight);
|
||||
|
|
@ -468,7 +833,47 @@ void DisassemblerGraphView::paintEvent(QPaintEvent* event)
|
|||
img.save(path);
|
||||
|
||||
//restore changes made to viewport for full render saving
|
||||
this->viewport()->resize(this->viewport()->width(), this->viewport()->height());
|
||||
this->viewport()->resize(size);
|
||||
|
||||
if(graphZoomMode)
|
||||
{
|
||||
this->horizontalScrollBar()->setValue(scrollbarPos.x());
|
||||
this->verticalScrollBar()->setValue(scrollbarPos.y());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::wheelEvent(QWheelEvent* event)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
return;
|
||||
|
||||
if (event->modifiers() & Qt::ControlModifier && graphZoomMode) {
|
||||
QPoint numDegrees = event->angleDelta() / 8;
|
||||
QPoint numSteps = numDegrees / 15;
|
||||
QPoint mousePosition = event->pos();
|
||||
|
||||
zoomBoost = 1;
|
||||
//Speed up zooming on large graphs by Ctrl+Shift
|
||||
if (event->modifiers() & Qt::ShiftModifier)
|
||||
zoomBoost = 2;
|
||||
|
||||
if (numSteps.y() > 0)
|
||||
{
|
||||
zoomDirection = 1;
|
||||
zoomIn(mousePosition);
|
||||
}
|
||||
else if (numSteps.y() < 0)
|
||||
{
|
||||
zoomDirection = -1;
|
||||
zoomOut(mousePosition);
|
||||
}
|
||||
|
||||
event->accept();
|
||||
}
|
||||
else
|
||||
{
|
||||
QAbstractScrollArea::wheelEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -477,8 +882,8 @@ bool DisassemblerGraphView::isMouseEventInBlock(QMouseEvent* event)
|
|||
//Convert coordinates to system used in blocks
|
||||
int xofs = this->horizontalScrollBar()->value();
|
||||
int yofs = this->verticalScrollBar()->value();
|
||||
int x = event->x() + xofs - this->renderXOfs;
|
||||
int y = event->y() + yofs - this->renderYOfs;
|
||||
int x = (event->x() + xofs - this->renderXOfs) / zoomLevel;
|
||||
int y = (event->y() + yofs - this->renderYOfs) / zoomLevel;
|
||||
|
||||
// Check each block for hits
|
||||
for(auto & blockIt : this->blocks)
|
||||
|
|
@ -502,8 +907,8 @@ duint DisassemblerGraphView::getInstrForMouseEvent(QMouseEvent* event)
|
|||
//Convert coordinates to system used in blocks
|
||||
int xofs = this->horizontalScrollBar()->value();
|
||||
int yofs = this->verticalScrollBar()->value();
|
||||
int x = event->x() + xofs - this->renderXOfs;
|
||||
int y = event->y() + yofs - this->renderYOfs;
|
||||
int x = (event->x() + xofs - this->renderXOfs) / zoomLevel;
|
||||
int y = (event->y() + yofs - this->renderYOfs) / zoomLevel;
|
||||
|
||||
//Check each block for hits
|
||||
for(auto & blockIt : this->blocks)
|
||||
|
|
@ -612,8 +1017,19 @@ bool DisassemblerGraphView::find_instr(duint addr, Instr & instrOut)
|
|||
|
||||
void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
||||
{
|
||||
if(!DbgIsDebugging())
|
||||
if(!DbgIsDebugging() || !this->ready)
|
||||
return;
|
||||
|
||||
bool inBlock = this->isMouseEventInBlock(event);
|
||||
|
||||
//Save click state for actions that need to maintain cursor position and can be triggered whether via menu or by key
|
||||
//TODO: transfer this to setupContextMenu() somehow
|
||||
if(event->button() == Qt::RightButton)
|
||||
{
|
||||
this->lastRightClickPosition.pos = event->pos();
|
||||
this->lastRightClickPosition.inBlock = inBlock;
|
||||
}
|
||||
|
||||
if(drawOverview)
|
||||
{
|
||||
if(event->button() == Qt::LeftButton)
|
||||
|
|
@ -636,7 +1052,7 @@ void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
|||
wMenu.exec(event->globalPos()); //execute context menu
|
||||
}
|
||||
}
|
||||
else if((event->button() == Qt::LeftButton || event->button() == Qt::RightButton) && this->isMouseEventInBlock(event))
|
||||
else if((event->button() == Qt::LeftButton || event->button() == Qt::RightButton) && inBlock)
|
||||
{
|
||||
//Check for click on a token and highlight it
|
||||
Token token;
|
||||
|
|
@ -655,9 +1071,7 @@ void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
|||
|
||||
if(event->button() == Qt::RightButton)
|
||||
{
|
||||
QMenu wMenu(this);
|
||||
mMenuBuilder->build(&wMenu);
|
||||
wMenu.exec(event->globalPos()); //execute context menu
|
||||
showContextMenu(event);
|
||||
}
|
||||
}
|
||||
else if(event->button() == Qt::LeftButton)
|
||||
|
|
@ -671,10 +1085,7 @@ void DisassemblerGraphView::mousePressEvent(QMouseEvent* event)
|
|||
}
|
||||
else if(event->button() == Qt::RightButton)
|
||||
{
|
||||
//Right click outside of block
|
||||
QMenu wMenu(this);
|
||||
mMenuBuilder->build(&wMenu);
|
||||
wMenu.exec(event->globalPos()); //execute context menu
|
||||
showContextMenu(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -698,6 +1109,8 @@ void DisassemblerGraphView::mouseMoveEvent(QMouseEvent* event)
|
|||
|
||||
void DisassemblerGraphView::mouseReleaseEvent(QMouseEvent* event)
|
||||
{
|
||||
this->viewport()->update();
|
||||
|
||||
if(event->button() == Qt::ForwardButton)
|
||||
gotoNextSlot();
|
||||
else if(event->button() == Qt::BackButton)
|
||||
|
|
@ -720,7 +1133,7 @@ void DisassemblerGraphView::mouseDoubleClickEvent(QMouseEvent* event)
|
|||
{
|
||||
toggleOverviewSlot();
|
||||
}
|
||||
else
|
||||
else if(!graphZoomMode || (zoomLevel > zoomOverviewValue))
|
||||
{
|
||||
duint instr = this->getInstrForMouseEvent(event);
|
||||
|
||||
|
|
@ -1371,7 +1784,21 @@ void DisassemblerGraphView::renderFunction(Function & func)
|
|||
//puts("Precompute coordinates for edges");
|
||||
|
||||
//Adjust scroll bars for new size
|
||||
auto areaSize = this->viewport()->size();
|
||||
QSize areaSize;
|
||||
if(this->viewportReady)
|
||||
{
|
||||
areaSize = this->viewport()->size();
|
||||
}
|
||||
else
|
||||
{
|
||||
//before graph tab is shown for the first time the viewport is kind of 98x28 so setting the parent size almost fixes this problem
|
||||
areaSize = this->parentWidget()->size() - QSize(20, 20);
|
||||
}
|
||||
|
||||
qreal sx = qreal(areaSize.width()) / qreal(this->width);
|
||||
qreal sy = qreal(areaSize.height()) / qreal(this->height);
|
||||
zoomMinimum = qMin(qMin(sx, sy) * (1 - zoomStep), 0.05); //if graph is very lagre
|
||||
|
||||
this->adjustSize(areaSize.width(), areaSize.height());
|
||||
puts("Adjust scroll bars for new size");
|
||||
|
||||
|
|
@ -1413,13 +1840,25 @@ void DisassemblerGraphView::show_cur_instr(bool force)
|
|||
int xofs = this->horizontalScrollBar()->value();
|
||||
int yofs = this->verticalScrollBar()->value();
|
||||
QRect viewportRect = this->viewport()->rect();
|
||||
|
||||
if(!viewportReady)
|
||||
{
|
||||
//before being shown for the first time viewport is kind of 98x28 so setting the parent size almost fixes this problem
|
||||
viewportRect.setSize(this->parentWidget()->size() - QSize(20, 20));
|
||||
}
|
||||
|
||||
QPoint translation(this->renderXOfs - xofs, this->renderYOfs - yofs);
|
||||
viewportRect.translate(-translation.x(), -translation.y());
|
||||
|
||||
//Adjust scaled viewport
|
||||
viewportRect.setWidth(viewportRect.width() / zoomLevel);
|
||||
viewportRect.setHeight(viewportRect.height() / zoomLevel);
|
||||
viewportRect.translate(-translation.x() / zoomLevel, -translation.y() / zoomLevel);
|
||||
|
||||
if(force || !viewportRect.contains(QRect(block.x + this->charWidth, block.y + this->charWidth,
|
||||
block.width - (2 * this->charWidth), block.height - (2 * this->charWidth))))
|
||||
{
|
||||
auto x = block.x + int(block.width / 2);
|
||||
auto y = block.y + (2 * this->charWidth) + int((row + 0.5) * this->charHeight);
|
||||
auto x = (block.x + int(block.width / 2)) * zoomLevel;
|
||||
auto y = (block.y + (2 * this->charWidth) + int((row + 0.5) * this->charHeight)) * zoomLevel;
|
||||
this->horizontalScrollBar()->setValue(x + this->renderXOfs -
|
||||
int(this->horizontalScrollBar()->pageStep() / 2));
|
||||
this->verticalScrollBar()->setValue(y + this->renderYOfs -
|
||||
|
|
@ -1501,6 +1940,20 @@ void DisassemblerGraphView::tokenizerConfigUpdatedSlot()
|
|||
|
||||
void DisassemblerGraphView::loadCurrentGraph()
|
||||
{
|
||||
if(ConfigBool("Gui", "GraphZoomMode"))
|
||||
{
|
||||
graphZoomMode = true;
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
}
|
||||
else
|
||||
{
|
||||
graphZoomMode = false;
|
||||
zoomLevel = 1;
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
|
||||
}
|
||||
|
||||
bool showGraphRva = ConfigBool("Gui", "ShowGraphRva");
|
||||
Analysis anal;
|
||||
anal.entry = currentGraph.entryPoint;
|
||||
|
|
@ -1647,11 +2100,27 @@ void DisassemblerGraphView::addReferenceAction(QMenu* menu, duint addr)
|
|||
menu->addAction(action);
|
||||
}
|
||||
|
||||
duint DisassemblerGraphView::zoomActionHelper()
|
||||
{
|
||||
if(!graphZoomMode || graphZoomMode && lastRightClickPosition.pos.isNull()) //old mode or zoom mode + shurtcut
|
||||
return cur_instr;
|
||||
else if(graphZoomMode && !(lastRightClickPosition.inBlock && zoomLevel > zoomOverviewValue)) //out of block or too small zoom value
|
||||
return 0;
|
||||
else
|
||||
return cur_instr;
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::setupContextMenu()
|
||||
{
|
||||
mMenuBuilder = new MenuBuilder(this, [](QMenu*)
|
||||
/* Unlike old style menu, the new one now depends on zoom level and cursor position.
|
||||
* There are several options for how menu will look like. This makes interaction more clear and predictable.
|
||||
* E.g clicking outside of block (especially at large zoom level) will set breakpoint menu hidden
|
||||
* as well as any action that needs text to be visible will also be hidden.
|
||||
* Notice: keyboard shortcuts still work - this implies that user understands what he is doing. */
|
||||
|
||||
mMenuBuilder = new MenuBuilder(this, [this](QMenu*)
|
||||
{
|
||||
return DbgIsDebugging();
|
||||
return DbgIsDebugging() && this->ready;
|
||||
});
|
||||
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon(QString("processor%1.png").arg(ArchValue("32", "64"))), tr("Follow in &Disassembler"), SLOT(followDisassemblerSlot()), "ActionGraphFollowDisassembler"), [this](QMenu*)
|
||||
|
|
@ -1662,11 +2131,23 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
|
||||
auto breakpointMenu = new BreakpointMenu(this, getActionHelperFuncs(), [this]()
|
||||
{
|
||||
return cur_instr;
|
||||
return zoomActionHelper();
|
||||
});
|
||||
breakpointMenu->build(mMenuBuilder);
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("&Comment"), SLOT(setCommentSlot()), "ActionSetComment"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("label.png"), tr("&Label"), SLOT(setLabelSlot()), "ActionSetLabel"));
|
||||
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("comment.png"), tr("&Comment"), SLOT(setCommentSlot()), "ActionSetComment"), [this](QMenu*)
|
||||
{
|
||||
return zoomActionHelper();
|
||||
});
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("label.png"), tr("&Label"), SLOT(setLabelSlot()), "ActionSetLabel"), [this](QMenu*)
|
||||
{
|
||||
return zoomActionHelper();
|
||||
});
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs.png"), tr("Xrefs..."), SLOT(xrefSlot()), "ActionXrefs"), [this](QMenu*)
|
||||
{
|
||||
return zoomActionHelper();
|
||||
});
|
||||
|
||||
MenuBuilder* gotoMenu = new MenuBuilder(this);
|
||||
gotoMenu->addAction(makeShortcutAction(DIcon("geolocation-goto.png"), tr("Expression"), SLOT(gotoExpressionSlot()), "ActionGotoExpression"));
|
||||
gotoMenu->addAction(makeShortcutAction(DIcon("cbp.png"), tr("Origin"), SLOT(gotoOriginSlot()), "ActionGotoOrigin"));
|
||||
|
|
@ -1680,6 +2161,8 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
});
|
||||
MenuBuilder* childrenAndParentMenu = new MenuBuilder(this, [this](QMenu * menu)
|
||||
{
|
||||
if(!zoomActionHelper())
|
||||
return false;
|
||||
duint cursorpos = get_cursor_pos();
|
||||
const DisassemblerBlock* currentBlock = nullptr;
|
||||
const Instr* currentInstruction = nullptr;
|
||||
|
|
@ -1717,10 +2200,31 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
gotoMenu->addSeparator();
|
||||
gotoMenu->addBuilder(childrenAndParentMenu);
|
||||
mMenuBuilder->addMenu(makeMenu(DIcon("goto.png"), tr("Go to")), gotoMenu);
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("xrefs.png"), tr("Xrefs..."), SLOT(xrefSlot()), "ActionXrefs"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("snowman.png"), tr("Decompile"), SLOT(decompileSlot()), "ActionGraphDecompile"));
|
||||
|
||||
mMenuBuilder->addAction(mZoomToCursor = makeShortcutAction(DIcon("zoom.png"), tr("&Zoom 100%"), SLOT(zoomToCursorSlot()), "ActionGraphZoomToCursor"), [this](QMenu*)
|
||||
{
|
||||
if(!graphZoomMode)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
});
|
||||
mMenuBuilder->addAction(mFitToWindow = makeShortcutAction(DIcon("fit.png"), tr("&Fit to window"), SLOT(fitToWindowSlot()), "ActionGraphFitToWindow"), [this](QMenu*)
|
||||
{
|
||||
if(!graphZoomMode)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
});
|
||||
|
||||
mMenuBuilder->addSeparator();
|
||||
mMenuBuilder->addAction(mToggleOverview = makeShortcutAction(DIcon("graph.png"), tr("&Overview"), SLOT(toggleOverviewSlot()), "ActionGraphToggleOverview"));
|
||||
mMenuBuilder->addAction(makeShortcutAction(DIcon("snowman.png"), tr("Decompile"), SLOT(decompileSlot()), "ActionGraphDecompile"));
|
||||
mMenuBuilder->addAction(mToggleOverview = makeShortcutAction(DIcon("graph.png"), tr("&Overview"), SLOT(toggleOverviewSlot()), "ActionGraphToggleOverview"), [this](QMenu*)
|
||||
{
|
||||
if(graphZoomMode)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
});
|
||||
mToggleOverview->setCheckable(true);
|
||||
mMenuBuilder->addAction(mToggleSummary = makeShortcutAction(DIcon("summary.png"), tr("S&ummary"), SLOT(toggleSummarySlot()), "ActionGraphToggleSummary"));
|
||||
mToggleSummary->setCheckable(true);
|
||||
|
|
@ -1745,6 +2249,15 @@ void DisassemblerGraphView::setupContextMenu()
|
|||
mMenuBuilder->loadFromConfig();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::showContextMenu(QMouseEvent* event)
|
||||
{
|
||||
QMenu wMenu(this);
|
||||
mMenuBuilder->build(&wMenu);
|
||||
wMenu.exec(event->globalPos());
|
||||
|
||||
lastRightClickPosition.pos = {};
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::keyPressEvent(QKeyEvent* event)
|
||||
{
|
||||
if(event->modifiers() != 0)
|
||||
|
|
@ -1774,10 +2287,12 @@ void DisassemblerGraphView::followDisassemblerSlot()
|
|||
|
||||
void DisassemblerGraphView::colorsUpdatedSlot()
|
||||
{
|
||||
disassemblyBackgroundColor = ConfigColor("GraphNodeBackgroundColor");
|
||||
if(!disassemblyBackgroundColor.alpha())
|
||||
disassemblyBackgroundColor = ConfigColor("DisassemblyBackgroundColor");
|
||||
disassemblyBackgroundColor = ConfigColor("DisassemblyBackgroundColor");
|
||||
graphNodeColor = ConfigColor("GraphNodeColor");
|
||||
graphNodeBackgroundColor = ConfigColor("GraphNodeBackgroundColor");
|
||||
if(!graphNodeBackgroundColor.alpha())
|
||||
graphNodeBackgroundColor = disassemblyBackgroundColor;
|
||||
graphCurrentShadowColor = ConfigColor("GraphCurrentShadowColor");
|
||||
disassemblySelectionColor = ConfigColor("DisassemblySelectionColor");
|
||||
disassemblyTracedColor = ConfigColor("DisassemblyTracedBackgroundColor");
|
||||
auto a = disassemblySelectionColor, b = disassemblyTracedColor;
|
||||
|
|
@ -2038,3 +2553,35 @@ void DisassemblerGraphView::followActionSlot()
|
|||
DbgCmdExecDirect(QString("graph %1, silent").arg(data).toUtf8().constData());
|
||||
}
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::fitToWindowSlot()
|
||||
{
|
||||
auto areaSize = viewport()->size();
|
||||
qreal sx = qreal(areaSize.width()) / qreal(this->width);
|
||||
qreal sy = qreal(areaSize.height()) / qreal(this->height);
|
||||
zoomLevelOld = zoomLevel;
|
||||
zoomLevel = qMin(qMin(sx, sy), qreal(1));
|
||||
zoomDirection = -1;
|
||||
this->adjustSize(areaSize.width(), areaSize.height(), QPoint(), true);
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
||||
void DisassemblerGraphView::zoomToCursorSlot()
|
||||
{
|
||||
QPoint pos;
|
||||
|
||||
if(!lastRightClickPosition.pos.isNull())
|
||||
{
|
||||
pos = lastRightClickPosition.pos;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos = this->mapFromGlobal(QCursor::pos());
|
||||
}
|
||||
zoomLevelOld = zoomLevel;
|
||||
zoomLevel = 1;
|
||||
zoomDirection = 1;
|
||||
auto areaSize = viewport()->size();
|
||||
this->adjustSize(areaSize.width(), areaSize.height(), pos);
|
||||
this->viewport()->update();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,10 +200,16 @@ public:
|
|||
Narrow,
|
||||
};
|
||||
|
||||
struct ClickPosition
|
||||
{
|
||||
QPoint pos = QPoint(0, 0);
|
||||
bool inBlock = false;
|
||||
};
|
||||
|
||||
DisassemblerGraphView(QWidget* parent = nullptr);
|
||||
~DisassemblerGraphView();
|
||||
void initFont();
|
||||
void adjustSize(int width, int height);
|
||||
void adjustSize(int viewportWidth, int viewportHeight, QPoint mousePosition = QPoint(0, 0), bool fitToWindow = false);
|
||||
void resizeEvent(QResizeEvent* event);
|
||||
duint get_cursor_pos();
|
||||
void set_cursor_pos(duint addr);
|
||||
|
|
@ -228,7 +234,6 @@ public:
|
|||
void computeGraphLayout(DisassemblerBlock & block);
|
||||
void setupContextMenu();
|
||||
void keyPressEvent(QKeyEvent* event);
|
||||
|
||||
template<typename T>
|
||||
using Matrix = std::vector<std::vector<T>>;
|
||||
using EdgesVector = Matrix<std::vector<bool>>;
|
||||
|
|
@ -242,6 +247,13 @@ public:
|
|||
bool navigate(duint addr);
|
||||
void fontChanged();
|
||||
void setGraphLayout(LayoutType layout);
|
||||
void paintZoom(QPainter & p, QRect & viewportRect, int xofs, int yofs);
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void showEvent(QShowEvent* event);
|
||||
void zoomIn(QPoint mousePosition);
|
||||
void zoomOut(QPoint mousePosition);
|
||||
void showContextMenu(QMouseEvent* event);
|
||||
duint zoomActionHelper();
|
||||
|
||||
VaHistory mHistory;
|
||||
|
||||
|
|
@ -274,8 +286,21 @@ public slots:
|
|||
void setLabelSlot();
|
||||
void xrefSlot();
|
||||
void decompileSlot();
|
||||
void fitToWindowSlot();
|
||||
void zoomToCursorSlot();
|
||||
|
||||
private:
|
||||
bool graphZoomMode;
|
||||
qreal zoomLevel;
|
||||
qreal zoomLevelOld;
|
||||
qreal zoomMinimum;
|
||||
qreal zoomMaximum;
|
||||
qreal zoomOverviewValue;
|
||||
qreal zoomStep;
|
||||
//qreal zoomScrollThreshold;
|
||||
int zoomDirection;
|
||||
int zoomBoost;
|
||||
ClickPosition lastRightClickPosition;
|
||||
QString status;
|
||||
Analysis analysis;
|
||||
duint function;
|
||||
|
|
@ -295,6 +320,7 @@ private:
|
|||
int scroll_base_y;
|
||||
bool scroll_mode;
|
||||
bool ready;
|
||||
bool viewportReady;
|
||||
int* desired_pos;
|
||||
std::unordered_map<duint, DisassemblerBlock> blocks;
|
||||
HighlightToken* highlight_token;
|
||||
|
|
@ -317,6 +343,8 @@ private:
|
|||
QAction* mToggleOverview;
|
||||
QAction* mToggleSummary;
|
||||
QAction* mToggleSyncOrigin;
|
||||
QAction* mFitToWindow;
|
||||
QAction* mZoomToCursor;
|
||||
|
||||
QColor disassemblyBackgroundColor;
|
||||
QColor disassemblySelectionColor;
|
||||
|
|
@ -334,12 +362,14 @@ private:
|
|||
QColor mCommentBackgroundColor;
|
||||
QColor mLabelColor;
|
||||
QColor mLabelBackgroundColor;
|
||||
QColor graphNodeColor;
|
||||
QColor mAddressColor;
|
||||
QColor mAddressBackgroundColor;
|
||||
QColor mCipColor;
|
||||
QColor mBreakpointColor;
|
||||
QColor mDisabledBreakpointColor;
|
||||
QColor graphNodeColor;
|
||||
QColor graphNodeBackgroundColor;
|
||||
QColor graphCurrentShadowColor;
|
||||
|
||||
BridgeCFGraph currentGraph;
|
||||
std::unordered_map<duint, duint> currentBlockMap;
|
||||
|
|
|
|||
|
|
@ -238,6 +238,7 @@ void SettingsDialog::LoadSettings()
|
|||
GetSettingBool("Gui", "NoForegroundWindow", &settings.guiNoForegroundWindow);
|
||||
GetSettingBool("Gui", "LoadSaveTabOrder", &settings.guiLoadSaveTabOrder);
|
||||
GetSettingBool("Gui", "ShowGraphRva", &settings.guiShowGraphRva);
|
||||
GetSettingBool("Gui", "GraphZoomMode", &settings.guiGraphZoomMode);
|
||||
GetSettingBool("Gui", "ShowExitConfirmation", &settings.guiShowExitConfirmation);
|
||||
GetSettingBool("Gui", "DisableAutoComplete", &settings.guiDisableAutoComplete);
|
||||
GetSettingBool("Gui", "AsciiAddressDumpMode", &settings.guiAsciiAddressDumpMode);
|
||||
|
|
@ -249,6 +250,7 @@ void SettingsDialog::LoadSettings()
|
|||
ui->chkNoForegroundWindow->setChecked(settings.guiNoForegroundWindow);
|
||||
ui->chkSaveLoadTabOrder->setChecked(settings.guiLoadSaveTabOrder);
|
||||
ui->chkShowGraphRva->setChecked(settings.guiShowGraphRva);
|
||||
ui->chkGraphZoomMode->setChecked(settings.guiGraphZoomMode);
|
||||
ui->chkShowExitConfirmation->setChecked(settings.guiShowExitConfirmation);
|
||||
ui->chkDisableAutoComplete->setChecked(settings.guiDisableAutoComplete);
|
||||
ui->chkAsciiAddressDumpMode->setChecked(settings.guiAsciiAddressDumpMode);
|
||||
|
|
@ -389,6 +391,7 @@ void SettingsDialog::SaveSettings()
|
|||
BridgeSettingSetUint("Gui", "NoForegroundWindow", settings.guiNoForegroundWindow);
|
||||
BridgeSettingSetUint("Gui", "LoadSaveTabOrder", settings.guiLoadSaveTabOrder);
|
||||
BridgeSettingSetUint("Gui", "ShowGraphRva", settings.guiShowGraphRva);
|
||||
BridgeSettingSetUint("Gui", "GraphZoomMode", settings.guiGraphZoomMode);
|
||||
BridgeSettingSetUint("Gui", "ShowExitConfirmation", settings.guiShowExitConfirmation);
|
||||
BridgeSettingSetUint("Gui", "DisableAutoComplete", settings.guiDisableAutoComplete);
|
||||
BridgeSettingSetUint("Gui", "AsciiAddressDumpMode", settings.guiAsciiAddressDumpMode);
|
||||
|
|
@ -870,6 +873,12 @@ void SettingsDialog::on_chkShowGraphRva_toggled(bool checked)
|
|||
settings.guiShowGraphRva = checked;
|
||||
}
|
||||
|
||||
void SettingsDialog::on_chkGraphZoomMode_toggled(bool checked)
|
||||
{
|
||||
bTokenizerConfigUpdated = true;
|
||||
settings.guiGraphZoomMode = checked;
|
||||
}
|
||||
|
||||
void SettingsDialog::on_chkShowExitConfirmation_toggled(bool checked)
|
||||
{
|
||||
settings.guiShowExitConfirmation = checked;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,7 @@ private slots:
|
|||
void on_editSymbolCache_textEdited(const QString & arg1);
|
||||
void on_chkUtf16LogRedirect_toggled(bool checked);
|
||||
void on_chkShowGraphRva_toggled(bool checked);
|
||||
void on_chkGraphZoomMode_toggled(bool checked);
|
||||
void on_chkUseLocalHelpFile_toggled(bool checked);
|
||||
void on_chkQueryProcessCookie_toggled(bool checked);
|
||||
void on_chkQueryWorkingSet_toggled(bool checked);
|
||||
|
|
@ -182,6 +183,7 @@ private:
|
|||
bool guiNoForegroundWindow;
|
||||
bool guiLoadSaveTabOrder;
|
||||
bool guiShowGraphRva;
|
||||
bool guiGraphZoomMode;
|
||||
bool guiShowExitConfirmation;
|
||||
bool guiDisableAutoComplete;
|
||||
bool guiAsciiAddressDumpMode;
|
||||
|
|
|
|||
|
|
@ -692,6 +692,13 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkGraphZoomMode">
|
||||
<property name="text">
|
||||
<string>Graph zoom mode (beta)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="chkShowExitConfirmation">
|
||||
<property name="text">
|
||||
|
|
|
|||
|
|
@ -213,6 +213,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultColors.insert("GraphJmpColor", QColor("#0148FB"));
|
||||
defaultColors.insert("GraphBrtrueColor", QColor("#387804"));
|
||||
defaultColors.insert("GraphBrfalseColor", QColor("#ED4630"));
|
||||
defaultColors.insert("GraphCurrentShadowColor", QColor("#473a3a"));
|
||||
defaultColors.insert("GraphRetShadowColor", QColor("#900000"));
|
||||
defaultColors.insert("GraphIndirectcallShadowColor", QColor("#008080"));
|
||||
defaultColors.insert("GraphBackgroundColor", Qt::transparent);
|
||||
|
|
@ -274,6 +275,7 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
guiBool.insert("SidebarWatchLabels", true);
|
||||
guiBool.insert("LoadSaveTabOrder", false);
|
||||
guiBool.insert("ShowGraphRva", false);
|
||||
guiBool.insert("GraphZoomMode", false);
|
||||
guiBool.insert("ShowExitConfirmation", true);
|
||||
guiBool.insert("DisableAutoComplete", false);
|
||||
//Named menu settings
|
||||
|
|
@ -577,6 +579,8 @@ Configuration::Configuration() : QObject(), noMoreMsgbox(false)
|
|||
defaultShortcuts.insert("ActionExecuteCommandScript", Shortcut({tr("Actions"), tr("Execute Script Command")}, "X"));
|
||||
defaultShortcuts.insert("ActionRefresh", Shortcut({tr("Actions"), tr("Refresh")}, "F5"));
|
||||
defaultShortcuts.insert("ActionGraph", Shortcut({tr("Actions"), tr("Graph")}, "G"));
|
||||
defaultShortcuts.insert("ActionGraphZoomToCursor", Shortcut({tr("Actions"), tr("Graph"), tr("Zoom to cursor")}, "Z"));
|
||||
defaultShortcuts.insert("ActionGraphFitToWindow", Shortcut({tr("Actions"), tr("Graph"), tr("Fit To Window")}, "Shift+Z"));
|
||||
defaultShortcuts.insert("ActionGraphFollowDisassembler", Shortcut({tr("Actions"), tr("Graph"), tr("Follow in disassembler")}, "Shift+Return"));
|
||||
defaultShortcuts.insert("ActionGraphSaveImage", Shortcut({tr("Actions"), tr("Graph"), tr("Save as image")}, "I"));
|
||||
defaultShortcuts.insert("ActionGraphToggleOverview", Shortcut({tr("Actions"), tr("Graph"), tr("Toggle overview")}, "O"));
|
||||
|
|
|
|||
Binary file not shown.
|
After Width: | Height: | Size: 535 B |
Binary file not shown.
|
After Width: | Height: | Size: 740 B |
|
|
@ -314,5 +314,7 @@
|
|||
<file>images/breakpoint_memory_read.png</file>
|
||||
<file>images/lib.png</file>
|
||||
<file>images/names.png</file>
|
||||
<file>images/fit.png</file>
|
||||
<file>images/zoom.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
|
|||
Loading…
Reference in New Issue