2017-10-12 19:55:15 +00:00
|
|
|
#include "DisassemblyWidget.h"
|
2017-10-11 21:07:32 +00:00
|
|
|
#include "menus/DisassemblyContextMenu.h"
|
|
|
|
#include "utils/HexAsciiHighlighter.h"
|
|
|
|
#include "utils/HexHighlighter.h"
|
2017-10-14 09:35:49 +00:00
|
|
|
#include "utils/Configuration.h"
|
2017-11-15 21:56:10 +00:00
|
|
|
#include "utils/Helpers.h"
|
2017-11-20 20:11:56 +00:00
|
|
|
#include "utils/TempConfig.h"
|
2017-11-02 06:48:32 +00:00
|
|
|
|
2017-10-16 19:00:47 +00:00
|
|
|
#include <QScrollBar>
|
2017-11-02 06:48:32 +00:00
|
|
|
#include <QJsonArray>
|
|
|
|
#include <QJsonObject>
|
|
|
|
#include <QVBoxLayout>
|
2017-11-03 11:31:20 +00:00
|
|
|
#include <QRegularExpression>
|
2017-12-13 14:30:00 +00:00
|
|
|
#include <QTextBlockUserData>
|
|
|
|
|
|
|
|
|
|
|
|
class DisassemblyTextBlockUserData: public QTextBlockUserData
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
DisassemblyLine line;
|
|
|
|
|
|
|
|
explicit DisassemblyTextBlockUserData(const DisassemblyLine &line)
|
|
|
|
{
|
|
|
|
this->line = line;
|
|
|
|
}
|
|
|
|
};
|
2017-11-02 06:48:32 +00:00
|
|
|
|
2017-12-16 13:01:58 +00:00
|
|
|
static DisassemblyTextBlockUserData *getUserData(const QTextBlock &block)
|
|
|
|
{
|
|
|
|
QTextBlockUserData *userData = block.userData();
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!userData) {
|
2017-12-16 13:01:58 +00:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
return static_cast<DisassemblyTextBlockUserData *>(userData);
|
|
|
|
}
|
|
|
|
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2018-03-16 21:46:57 +00:00
|
|
|
DisassemblyWidget::DisassemblyWidget(MainWindow *main, QAction *action)
|
|
|
|
: CutterDockWidget(main, action)
|
2017-11-03 11:31:20 +00:00
|
|
|
, mCtxMenu(new DisassemblyContextMenu(this))
|
|
|
|
, mDisasScrollArea(new DisassemblyScrollArea(this))
|
|
|
|
, mDisasTextEdit(new DisassemblyTextEdit(this))
|
2018-05-25 14:30:59 +00:00
|
|
|
, seekable(new CutterSeekableWidget(this))
|
2017-10-11 21:07:32 +00:00
|
|
|
{
|
2017-11-02 06:48:32 +00:00
|
|
|
topOffset = bottomOffset = RVA_INVALID;
|
2017-12-16 13:01:58 +00:00
|
|
|
cursorLineOffset = 0;
|
|
|
|
seekFromCursor = false;
|
2017-11-02 06:48:32 +00:00
|
|
|
|
2017-12-21 15:47:36 +00:00
|
|
|
setWindowTitle(tr("Disassembly"));
|
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
QVBoxLayout *layout = new QVBoxLayout();
|
|
|
|
layout->addWidget(mDisasTextEdit);
|
|
|
|
layout->setMargin(0);
|
|
|
|
mDisasScrollArea->viewport()->setLayout(layout);
|
|
|
|
mDisasScrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
|
|
|
|
|
|
|
setWidget(mDisasScrollArea);
|
|
|
|
|
2017-10-12 19:55:15 +00:00
|
|
|
setAllowedAreas(Qt::AllDockWidgetAreas);
|
|
|
|
setObjectName("DisassemblyWidget");
|
2017-11-30 14:00:22 +00:00
|
|
|
|
|
|
|
setupFonts();
|
|
|
|
setupColors();
|
|
|
|
|
|
|
|
maxLines = 0;
|
|
|
|
updateMaxLines();
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
mDisasTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
2017-10-14 09:35:49 +00:00
|
|
|
mDisasTextEdit->setFont(Config()->getFont());
|
2017-10-16 19:00:47 +00:00
|
|
|
mDisasTextEdit->setReadOnly(true);
|
2017-11-02 06:48:32 +00:00
|
|
|
mDisasTextEdit->setLineWrapMode(QPlainTextEdit::WidgetWidth);
|
|
|
|
// wrapping breaks readCurrentDisassemblyOffset() at the moment :-(
|
|
|
|
mDisasTextEdit->setWordWrapMode(QTextOption::NoWrap);
|
2017-10-11 21:07:32 +00:00
|
|
|
|
|
|
|
// Increase asm text edit margin
|
|
|
|
QTextDocument *asm_docu = mDisasTextEdit->document();
|
|
|
|
asm_docu->setDocumentMargin(10);
|
|
|
|
|
|
|
|
// Event filter to intercept double clicks in the textbox
|
|
|
|
mDisasTextEdit->viewport()->installEventFilter(this);
|
|
|
|
|
|
|
|
// Set Disas context menu
|
|
|
|
mDisasTextEdit->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
|
|
connect(mDisasTextEdit, SIGNAL(customContextMenuRequested(const QPoint &)),
|
|
|
|
this, SLOT(showDisasContextMenu(const QPoint &)));
|
|
|
|
|
2017-11-04 11:46:29 +00:00
|
|
|
|
|
|
|
// Space to switch to graph
|
|
|
|
QShortcut *graphShortcut = new QShortcut(QKeySequence(Qt::Key_Space), this);
|
|
|
|
graphShortcut->setContext(Qt::WidgetWithChildrenShortcut);
|
2018-03-21 20:32:32 +00:00
|
|
|
connect(graphShortcut, &QShortcut::activated, this, [] {
|
2017-11-04 11:46:29 +00:00
|
|
|
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Graph);
|
|
|
|
Core()->triggerRaisePrioritizedMemoryWidget();
|
|
|
|
});
|
|
|
|
|
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
connect(mDisasScrollArea, SIGNAL(scrollLines(int)), this, SLOT(scrollInstructions(int)));
|
|
|
|
connect(mDisasScrollArea, SIGNAL(disassemblyResized()), this, SLOT(updateMaxLines()));
|
|
|
|
|
|
|
|
connectCursorPositionChanged(false);
|
2018-03-21 20:32:32 +00:00
|
|
|
connect(mDisasTextEdit->verticalScrollBar(), &QScrollBar::valueChanged, this, [ = ](int value) {
|
|
|
|
if (value != 0) {
|
2017-11-02 06:48:32 +00:00
|
|
|
mDisasTextEdit->verticalScrollBar()->setValue(0);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
connect(Core(), SIGNAL(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)), this,
|
|
|
|
SLOT(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)));
|
2017-11-04 11:46:29 +00:00
|
|
|
connect(Core(), SIGNAL(commentsChanged()), this, SLOT(refreshDisasm()));
|
2017-12-03 20:23:02 +00:00
|
|
|
connect(Core(), SIGNAL(flagsChanged()), this, SLOT(refreshDisasm()));
|
2017-12-11 13:07:12 +00:00
|
|
|
connect(Core(), SIGNAL(functionsChanged()), this, SLOT(refreshDisasm()));
|
2018-03-21 20:32:32 +00:00
|
|
|
connect(Core(), SIGNAL(functionRenamed(const QString &, const QString &)), this,
|
|
|
|
SLOT(refreshDisasm()));
|
2017-11-30 21:30:51 +00:00
|
|
|
connect(Core(), SIGNAL(varsChanged()), this, SLOT(refreshDisasm()));
|
2017-11-07 08:16:49 +00:00
|
|
|
connect(Core(), SIGNAL(asmOptionsChanged()), this, SLOT(refreshDisasm()));
|
2017-11-28 13:13:22 +00:00
|
|
|
connect(Core(), &CutterCore::instructionChanged, this, [this](RVA offset) {
|
2018-03-21 20:32:32 +00:00
|
|
|
if (offset >= topOffset && offset <= bottomOffset) {
|
2017-11-28 13:13:22 +00:00
|
|
|
refreshDisasm();
|
|
|
|
}
|
|
|
|
});
|
2018-07-01 21:29:38 +00:00
|
|
|
connect(Core(), SIGNAL(refreshCodeViews()), this, SLOT(refreshDisasm()));
|
2017-11-04 11:46:29 +00:00
|
|
|
|
2017-10-14 09:35:49 +00:00
|
|
|
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdatedSlot()));
|
2017-11-20 11:23:37 +00:00
|
|
|
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
|
2017-11-04 11:46:29 +00:00
|
|
|
|
|
|
|
connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) {
|
2018-03-21 20:32:32 +00:00
|
|
|
if (visibility) {
|
2017-11-04 11:46:29 +00:00
|
|
|
Core()->setMemoryWidgetPriority(CutterCore::MemoryWidgetType::Disassembly);
|
|
|
|
}
|
|
|
|
});
|
2017-11-19 12:56:10 +00:00
|
|
|
|
|
|
|
connect(Core(), &CutterCore::refreshAll, this, [this]() {
|
2018-06-27 15:33:21 +00:00
|
|
|
refreshDisasm(seekable->getOffset());
|
2017-11-19 12:56:10 +00:00
|
|
|
});
|
2017-11-28 15:42:40 +00:00
|
|
|
|
2017-12-02 15:43:21 +00:00
|
|
|
connect(mCtxMenu, SIGNAL(copy()), mDisasTextEdit, SLOT(copy()));
|
|
|
|
|
2017-11-28 15:42:40 +00:00
|
|
|
// Dirty
|
|
|
|
QShortcut *shortcut_escape = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
|
|
|
shortcut_escape->setContext(Qt::WidgetShortcut);
|
|
|
|
connect(shortcut_escape, SIGNAL(activated()), this, SLOT(seekPrev()));
|
2017-12-16 13:01:58 +00:00
|
|
|
|
2018-05-25 14:30:59 +00:00
|
|
|
mCtxMenu->addSeparator();
|
|
|
|
syncIt.setText(tr("Sync/unsync offset"));
|
|
|
|
mCtxMenu->addAction(&syncIt);
|
|
|
|
connect(&syncIt, SIGNAL(triggered(bool)), this, SLOT(toggleSync()));
|
|
|
|
connect(seekable, &CutterSeekableWidget::seekChanged, this, &DisassemblyWidget::on_seekChanged);
|
2017-12-16 13:01:58 +00:00
|
|
|
|
|
|
|
#define ADD_SHORTCUT(ksq, slot) { \
|
|
|
|
QShortcut *s = new QShortcut((ksq), this); \
|
|
|
|
s->setContext(Qt::WidgetShortcut); \
|
|
|
|
connect(s, &QShortcut::activated, this, (slot)); \
|
|
|
|
}
|
2018-03-21 20:32:32 +00:00
|
|
|
ADD_SHORTCUT(QKeySequence(Qt::Key_J), [this]() {
|
|
|
|
moveCursorRelative(false, false);
|
|
|
|
})
|
|
|
|
ADD_SHORTCUT(QKeySequence::MoveToNextLine, [this]() {
|
|
|
|
moveCursorRelative(false, false);
|
|
|
|
})
|
|
|
|
ADD_SHORTCUT(QKeySequence(Qt::Key_K), [this]() {
|
|
|
|
moveCursorRelative(true, false);
|
|
|
|
})
|
|
|
|
ADD_SHORTCUT(QKeySequence::MoveToPreviousLine, [this]() {
|
|
|
|
moveCursorRelative(true, false);
|
|
|
|
})
|
|
|
|
ADD_SHORTCUT(QKeySequence::MoveToNextPage, [this]() {
|
|
|
|
moveCursorRelative(false, true);
|
|
|
|
})
|
|
|
|
ADD_SHORTCUT(QKeySequence::MoveToPreviousPage, [this]() {
|
|
|
|
moveCursorRelative(true, true);
|
|
|
|
})
|
2018-06-15 00:03:22 +00:00
|
|
|
ADD_SHORTCUT(QKeySequence(Qt::CTRL + Qt::Key_Plus), &DisassemblyWidget::zoomIn)
|
|
|
|
ADD_SHORTCUT(QKeySequence(Qt::CTRL + Qt::Key_Minus), &DisassemblyWidget::zoomOut)
|
2017-12-16 13:01:58 +00:00
|
|
|
#undef ADD_SHORTCUT
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
|
|
|
|
2018-05-25 14:30:59 +00:00
|
|
|
void DisassemblyWidget::toggleSync()
|
|
|
|
{
|
|
|
|
QString windowTitle = tr("Disassembly");
|
|
|
|
seekable->toggleSyncWithCore();
|
|
|
|
if (seekable->getSyncWithCore()) {
|
|
|
|
setWindowTitle(windowTitle);
|
|
|
|
} else {
|
|
|
|
setWindowTitle(windowTitle + " (not synced)");
|
|
|
|
seekable->setIndependentOffset(Core()->getOffset());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
QWidget *DisassemblyWidget::getTextWidget()
|
2017-10-22 10:21:44 +00:00
|
|
|
{
|
|
|
|
return mDisasTextEdit;
|
|
|
|
}
|
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
void DisassemblyWidget::refreshDisasm(RVA offset)
|
2017-10-22 13:55:42 +00:00
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (offset != RVA_INVALID) {
|
2017-11-02 06:48:32 +00:00
|
|
|
topOffset = offset;
|
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (topOffset == RVA_INVALID) {
|
2017-12-04 13:11:05 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (maxLines <= 0) {
|
2017-11-18 12:56:48 +00:00
|
|
|
connectCursorPositionChanged(true);
|
2017-11-02 06:48:32 +00:00
|
|
|
mDisasTextEdit->clear();
|
2017-11-18 12:56:48 +00:00
|
|
|
connectCursorPositionChanged(false);
|
2017-11-02 06:48:32 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2018-08-12 16:20:16 +00:00
|
|
|
breakpoints = Core()->getBreakpointsAddresses();
|
2017-11-02 06:48:32 +00:00
|
|
|
int horizontalScrollValue = mDisasTextEdit->horizontalScrollBar()->value();
|
|
|
|
mDisasTextEdit->setLockScroll(true); // avoid flicker
|
2018-03-21 20:32:32 +00:00
|
|
|
|
2017-12-13 14:30:00 +00:00
|
|
|
QList<DisassemblyLine> disassemblyLines;
|
|
|
|
{
|
|
|
|
TempConfig tempConfig;
|
|
|
|
tempConfig.set("scr.html", true)
|
2018-03-21 20:32:32 +00:00
|
|
|
.set("scr.color", COLOR_MODE_16M);
|
2017-12-13 14:30:00 +00:00
|
|
|
disassemblyLines = Core()->disassembleLines(topOffset, maxLines);
|
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
connectCursorPositionChanged(true);
|
2017-10-22 13:55:42 +00:00
|
|
|
|
2017-12-13 14:30:00 +00:00
|
|
|
mDisasTextEdit->document()->clear();
|
|
|
|
QTextCursor cursor(mDisasTextEdit->document());
|
2018-08-12 16:20:16 +00:00
|
|
|
QTextBlockFormat regular = cursor.blockFormat();
|
2018-03-21 20:32:32 +00:00
|
|
|
for (DisassemblyLine line : disassemblyLines) {
|
2018-04-15 17:06:05 +00:00
|
|
|
if (line.offset < topOffset) { // overflow
|
|
|
|
break;
|
|
|
|
}
|
2017-12-13 14:30:00 +00:00
|
|
|
cursor.insertHtml(line.text);
|
2018-09-05 12:47:09 +00:00
|
|
|
if(Core()->isBreakpoint(breakpoints, line.offset)) {
|
2018-08-12 16:20:16 +00:00
|
|
|
QTextBlockFormat f;
|
|
|
|
f.setBackground(ConfigColor("gui.breakpoint_background"));
|
|
|
|
cursor.setBlockFormat(f);
|
|
|
|
}
|
2017-12-13 14:30:00 +00:00
|
|
|
auto a = new DisassemblyTextBlockUserData(line);
|
|
|
|
cursor.block().setUserData(a);
|
|
|
|
cursor.insertBlock();
|
2018-08-12 16:20:16 +00:00
|
|
|
cursor.setBlockFormat(regular);
|
2017-12-13 14:30:00 +00:00
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2018-04-15 17:06:05 +00:00
|
|
|
if (!disassemblyLines.isEmpty()) {
|
|
|
|
bottomOffset = disassemblyLines[qMin(disassemblyLines.size(), maxLines) - 1].offset;
|
|
|
|
if (bottomOffset < topOffset) {
|
|
|
|
bottomOffset = RVA_MAX;
|
|
|
|
}
|
|
|
|
} else {
|
2017-11-02 06:48:32 +00:00
|
|
|
bottomOffset = topOffset;
|
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-11-20 10:04:03 +00:00
|
|
|
// remove additional lines
|
2018-04-15 17:06:05 +00:00
|
|
|
QTextCursor tc = mDisasTextEdit->textCursor();
|
|
|
|
tc.movePosition(QTextCursor::Start);
|
|
|
|
tc.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, maxLines - 1);
|
2017-11-20 10:04:03 +00:00
|
|
|
tc.movePosition(QTextCursor::EndOfLine);
|
|
|
|
tc.movePosition(QTextCursor::End, QTextCursor::KeepAnchor);
|
|
|
|
tc.removeSelectedText();
|
|
|
|
|
2018-04-15 17:06:05 +00:00
|
|
|
connectCursorPositionChanged(false);
|
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
updateCursorPosition();
|
|
|
|
|
|
|
|
mDisasTextEdit->setLockScroll(false);
|
|
|
|
mDisasTextEdit->horizontalScrollBar()->setValue(horizontalScrollValue);
|
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
|
|
|
|
void DisassemblyWidget::scrollInstructions(int count)
|
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (count == 0) {
|
2017-11-02 06:48:32 +00:00
|
|
|
return;
|
2017-10-22 13:55:42 +00:00
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
RVA offset;
|
2018-03-21 20:32:32 +00:00
|
|
|
if (count > 0) {
|
2017-11-02 06:48:32 +00:00
|
|
|
offset = Core()->nextOpAddr(topOffset, count);
|
2018-04-15 17:06:05 +00:00
|
|
|
if (offset < topOffset) {
|
|
|
|
offset = RVA_MAX;
|
|
|
|
}
|
2018-03-21 20:32:32 +00:00
|
|
|
} else {
|
2017-11-02 06:48:32 +00:00
|
|
|
offset = Core()->prevOpAddr(topOffset, -count);
|
2018-04-15 17:06:05 +00:00
|
|
|
if (offset > topOffset) {
|
|
|
|
offset = 0;
|
|
|
|
}
|
2017-11-02 06:48:32 +00:00
|
|
|
}
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
refreshDisasm(offset);
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-11-20 10:04:03 +00:00
|
|
|
bool DisassemblyWidget::updateMaxLines()
|
2017-11-02 06:48:32 +00:00
|
|
|
{
|
2017-11-15 21:56:10 +00:00
|
|
|
int currentMaxLines = qhelpers::getMaxFullyDisplayedLines(mDisasTextEdit);
|
2017-11-20 10:04:03 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (currentMaxLines != maxLines) {
|
2017-11-02 06:48:32 +00:00
|
|
|
maxLines = currentMaxLines;
|
|
|
|
refreshDisasm();
|
2017-11-20 10:04:03 +00:00
|
|
|
return true;
|
2017-11-02 06:48:32 +00:00
|
|
|
}
|
2017-11-20 10:04:03 +00:00
|
|
|
|
|
|
|
return false;
|
2017-11-02 06:48:32 +00:00
|
|
|
}
|
|
|
|
|
2018-06-15 00:03:22 +00:00
|
|
|
void DisassemblyWidget::zoomIn() {
|
|
|
|
mDisasTextEdit->zoomIn();
|
|
|
|
updateMaxLines();
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisassemblyWidget::zoomOut() {
|
|
|
|
mDisasTextEdit->zoomOut();
|
|
|
|
updateMaxLines();
|
|
|
|
}
|
|
|
|
|
2017-10-22 13:55:42 +00:00
|
|
|
void DisassemblyWidget::highlightCurrentLine()
|
2017-10-11 21:07:32 +00:00
|
|
|
{
|
2017-10-22 13:55:42 +00:00
|
|
|
QList<QTextEdit::ExtraSelection> extraSelections;
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-12-02 15:03:55 +00:00
|
|
|
QColor highlightColor = ConfigColor("highlight");
|
2018-06-22 15:57:15 +00:00
|
|
|
QColor highlightPCColor = ConfigColor("highlightPC");
|
2018-05-10 14:08:03 +00:00
|
|
|
QColor highlightWordColor = ConfigColor("highlightWord");
|
2017-12-02 15:03:55 +00:00
|
|
|
highlightWordColor.setAlpha(128);
|
|
|
|
QColor highlightWordCurrentLineColor = ConfigColor("gui.background");
|
|
|
|
highlightWordCurrentLineColor.setAlpha(128);
|
|
|
|
|
2017-10-22 13:55:42 +00:00
|
|
|
// Highlight the current word
|
|
|
|
QTextCursor cursor = mDisasTextEdit->textCursor();
|
|
|
|
cursor.select(QTextCursor::WordUnderCursor);
|
2017-12-02 15:03:55 +00:00
|
|
|
QString searchString = cursor.selectedText();
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-12-02 15:03:55 +00:00
|
|
|
cursor.movePosition(QTextCursor::StartOfLine);
|
|
|
|
int listStartPos = cursor.position();
|
|
|
|
cursor.movePosition(QTextCursor::EndOfLine);
|
|
|
|
int lineEndPos = cursor.position();
|
2017-10-22 13:55:42 +00:00
|
|
|
|
2018-09-05 12:47:09 +00:00
|
|
|
// Highlight the current line
|
|
|
|
QTextEdit::ExtraSelection highlightSelection;
|
|
|
|
highlightSelection.cursor = cursor;
|
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::Start);
|
|
|
|
while (true) {
|
|
|
|
RVA lineOffset = readDisassemblyOffset(highlightSelection.cursor);
|
|
|
|
if (lineOffset == seekable->getOffset()) {
|
|
|
|
highlightSelection.format.setBackground(highlightColor);
|
|
|
|
highlightSelection.format.setProperty(QTextFormat::FullWidthSelection, true);
|
|
|
|
highlightSelection.cursor.clearSelection();
|
|
|
|
extraSelections.append(highlightSelection);
|
|
|
|
} else if (lineOffset != RVA_INVALID && lineOffset > seekable->getOffset()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::EndOfLine);
|
|
|
|
if (highlightSelection.cursor.atEnd()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::Down);
|
|
|
|
}
|
|
|
|
|
2017-12-02 15:03:55 +00:00
|
|
|
// Highlight all the words in the document same as the current one
|
2017-10-22 13:55:42 +00:00
|
|
|
QTextDocument *document = mDisasTextEdit->document();
|
|
|
|
|
|
|
|
highlightSelection.cursor = cursor;
|
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::Start, QTextCursor::MoveAnchor);
|
2017-12-02 15:03:55 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
while (!highlightSelection.cursor.isNull() && !highlightSelection.cursor.atEnd()) {
|
|
|
|
highlightSelection.cursor = document->find(searchString, highlightSelection.cursor,
|
|
|
|
QTextDocument::FindWholeWords);
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!highlightSelection.cursor.isNull()) {
|
|
|
|
if (highlightSelection.cursor.position() >= listStartPos
|
|
|
|
&& highlightSelection.cursor.position() <= lineEndPos) {
|
2017-12-02 15:03:55 +00:00
|
|
|
highlightSelection.format.setBackground(highlightWordCurrentLineColor);
|
2018-03-21 20:32:32 +00:00
|
|
|
} else {
|
2017-12-02 15:03:55 +00:00
|
|
|
highlightSelection.format.setBackground(highlightWordColor);
|
|
|
|
}
|
|
|
|
|
2017-10-22 13:55:42 +00:00
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::EndOfWord, QTextCursor::KeepAnchor);
|
|
|
|
extraSelections.append(highlightSelection);
|
|
|
|
}
|
|
|
|
}
|
2017-10-13 13:53:23 +00:00
|
|
|
|
2018-06-22 15:57:15 +00:00
|
|
|
// highlight PC line
|
|
|
|
RVA PCAddr = Core()->getProgramCounterValue();
|
|
|
|
highlightSelection.cursor = cursor;
|
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::Start);
|
|
|
|
if (PCAddr != RVA_INVALID) {
|
|
|
|
while (true) {
|
|
|
|
RVA lineOffset = readDisassemblyOffset(highlightSelection.cursor);
|
|
|
|
if (lineOffset == PCAddr) {
|
|
|
|
highlightSelection.format.setBackground(highlightPCColor);
|
|
|
|
highlightSelection.format.setProperty(QTextFormat::FullWidthSelection, true);
|
|
|
|
highlightSelection.cursor.clearSelection();
|
|
|
|
extraSelections.append(highlightSelection);
|
|
|
|
} else if (lineOffset != RVA_INVALID && lineOffset > PCAddr) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::EndOfLine);
|
|
|
|
if (highlightSelection.cursor.atEnd()) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
highlightSelection.cursor.movePosition(QTextCursor::Down);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-22 13:55:42 +00:00
|
|
|
mDisasTextEdit->setExtraSelections(extraSelections);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisassemblyWidget::showDisasContextMenu(const QPoint &pt)
|
|
|
|
{
|
2017-11-03 11:31:20 +00:00
|
|
|
mCtxMenu->exec(mDisasTextEdit->mapToGlobal(pt));
|
2017-10-22 13:55:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
RVA DisassemblyWidget::readCurrentDisassemblyOffset()
|
2017-11-28 11:56:38 +00:00
|
|
|
{
|
|
|
|
QTextCursor tc = mDisasTextEdit->textCursor();
|
|
|
|
return readDisassemblyOffset(tc);
|
|
|
|
}
|
|
|
|
|
|
|
|
RVA DisassemblyWidget::readDisassemblyOffset(QTextCursor tc)
|
2017-10-22 13:55:42 +00:00
|
|
|
{
|
2017-12-16 13:01:58 +00:00
|
|
|
auto userData = getUserData(tc.block());
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!userData) {
|
2017-12-13 14:30:00 +00:00
|
|
|
return RVA_INVALID;
|
2017-10-22 13:55:42 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 13:01:58 +00:00
|
|
|
return userData->line.offset;
|
2017-10-22 13:55:42 +00:00
|
|
|
}
|
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
void DisassemblyWidget::updateCursorPosition()
|
2017-10-22 13:55:42 +00:00
|
|
|
{
|
2018-05-25 14:30:59 +00:00
|
|
|
RVA offset = seekable->getOffset();
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-12-02 13:27:15 +00:00
|
|
|
// already fine where it is?
|
|
|
|
RVA currentLineOffset = readCurrentDisassemblyOffset();
|
2018-03-21 20:32:32 +00:00
|
|
|
if (currentLineOffset == offset) {
|
2017-12-02 13:27:15 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
connectCursorPositionChanged(true);
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (offset < topOffset || (offset > bottomOffset && bottomOffset != RVA_INVALID)) {
|
2017-11-02 06:48:32 +00:00
|
|
|
mDisasTextEdit->moveCursor(QTextCursor::Start);
|
|
|
|
mDisasTextEdit->setExtraSelections({});
|
2018-03-21 20:32:32 +00:00
|
|
|
} else {
|
2017-11-02 06:48:32 +00:00
|
|
|
RVA currentCursorOffset = readCurrentDisassemblyOffset();
|
|
|
|
QTextCursor originalCursor = mDisasTextEdit->textCursor();
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
QTextCursor cursor = originalCursor;
|
|
|
|
cursor.movePosition(QTextCursor::Start);
|
2017-10-11 21:07:32 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
while (true) {
|
2017-12-02 13:27:15 +00:00
|
|
|
RVA lineOffset = readDisassemblyOffset(cursor);
|
2018-03-21 20:32:32 +00:00
|
|
|
if (lineOffset == offset) {
|
|
|
|
if (cursorLineOffset > 0) {
|
2017-12-16 13:01:58 +00:00
|
|
|
cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, cursorLineOffset);
|
|
|
|
}
|
|
|
|
|
2017-12-02 13:27:15 +00:00
|
|
|
mDisasTextEdit->setTextCursor(cursor);
|
2017-11-02 06:48:32 +00:00
|
|
|
highlightCurrentLine();
|
|
|
|
break;
|
2018-03-21 20:32:32 +00:00
|
|
|
} else if (lineOffset != RVA_INVALID && lineOffset > offset) {
|
2017-11-02 06:48:32 +00:00
|
|
|
mDisasTextEdit->moveCursor(QTextCursor::Start);
|
|
|
|
mDisasTextEdit->setExtraSelections({});
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor.movePosition(QTextCursor::EndOfLine);
|
2018-03-21 20:32:32 +00:00
|
|
|
if (cursor.atEnd()) {
|
2017-11-02 06:48:32 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cursor.movePosition(QTextCursor::Down);
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
2017-11-02 06:48:32 +00:00
|
|
|
|
|
|
|
// this is true if a seek came from the user clicking on a line.
|
|
|
|
// then the cursor should be restored 1:1 to retain selection and cursor position.
|
2018-03-21 20:32:32 +00:00
|
|
|
if (currentCursorOffset == offset) {
|
2017-11-02 06:48:32 +00:00
|
|
|
mDisasTextEdit->setTextCursor(originalCursor);
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
|
|
|
}
|
2017-11-02 06:48:32 +00:00
|
|
|
connectCursorPositionChanged(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisassemblyWidget::connectCursorPositionChanged(bool disconnect)
|
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (disconnect) {
|
|
|
|
QObject::disconnect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this,
|
|
|
|
SLOT(cursorPositionChanged()));
|
|
|
|
} else {
|
2017-11-02 06:48:32 +00:00
|
|
|
connect(mDisasTextEdit, SIGNAL(cursorPositionChanged()), this, SLOT(cursorPositionChanged()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisassemblyWidget::cursorPositionChanged()
|
|
|
|
{
|
|
|
|
RVA offset = readCurrentDisassemblyOffset();
|
2017-12-16 13:01:58 +00:00
|
|
|
|
|
|
|
cursorLineOffset = 0;
|
|
|
|
QTextCursor c = mDisasTextEdit->textCursor();
|
2018-03-21 20:32:32 +00:00
|
|
|
while (c.blockNumber() > 0) {
|
2017-12-16 13:01:58 +00:00
|
|
|
c.movePosition(QTextCursor::PreviousBlock);
|
2018-03-21 20:32:32 +00:00
|
|
|
if (readDisassemblyOffset(c) != offset) {
|
2017-12-16 13:01:58 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
cursorLineOffset++;
|
|
|
|
}
|
|
|
|
|
|
|
|
seekFromCursor = true;
|
2018-05-25 14:30:59 +00:00
|
|
|
seekable->seek(offset);
|
2017-12-16 13:01:58 +00:00
|
|
|
seekFromCursor = false;
|
2017-12-02 13:27:15 +00:00
|
|
|
highlightCurrentLine();
|
2017-12-02 15:43:21 +00:00
|
|
|
mCtxMenu->setCanCopy(mDisasTextEdit->textCursor().hasSelection());
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
|
|
|
|
2017-12-16 13:01:58 +00:00
|
|
|
void DisassemblyWidget::moveCursorRelative(bool up, bool page)
|
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (page) {
|
2017-12-17 14:11:27 +00:00
|
|
|
RVA offset;
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!up) {
|
2017-12-17 14:11:27 +00:00
|
|
|
offset = Core()->nextOpAddr(bottomOffset, 1);
|
2018-04-15 17:06:05 +00:00
|
|
|
if (offset < bottomOffset) {
|
|
|
|
offset = RVA_MAX;
|
|
|
|
}
|
2018-03-21 20:32:32 +00:00
|
|
|
} else {
|
2017-12-17 14:11:27 +00:00
|
|
|
offset = Core()->prevOpAddr(topOffset, maxLines);
|
2018-04-15 17:06:05 +00:00
|
|
|
if (offset > topOffset) {
|
|
|
|
offset = 0;
|
|
|
|
} else {
|
|
|
|
// disassembly from calculated offset may have more than maxLines lines
|
|
|
|
// move some instructions down if necessary.
|
|
|
|
|
|
|
|
auto lines = Core()->disassembleLines(offset, maxLines).toVector();
|
|
|
|
int oldTopLine;
|
|
|
|
for (oldTopLine = lines.length(); oldTopLine > 0; oldTopLine--) {
|
|
|
|
if (lines[oldTopLine - 1].offset < topOffset) {
|
|
|
|
break;
|
|
|
|
}
|
2017-12-17 14:11:27 +00:00
|
|
|
}
|
2017-12-16 13:01:58 +00:00
|
|
|
|
2018-04-15 17:06:05 +00:00
|
|
|
int overflowLines = oldTopLine - maxLines;
|
|
|
|
if (overflowLines > 0) {
|
|
|
|
while (lines[overflowLines - 1].offset == lines[overflowLines].offset
|
2018-03-21 20:32:32 +00:00
|
|
|
&& overflowLines < lines.length() - 1) {
|
2018-04-15 17:06:05 +00:00
|
|
|
overflowLines++;
|
|
|
|
}
|
|
|
|
offset = lines[overflowLines].offset;
|
2017-12-17 14:11:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
refreshDisasm(offset);
|
2018-03-21 20:32:32 +00:00
|
|
|
} else { // normal arrow keys
|
2017-12-17 14:11:27 +00:00
|
|
|
int blockCount = mDisasTextEdit->blockCount();
|
2018-03-21 20:32:32 +00:00
|
|
|
if (blockCount < 1) {
|
2017-12-17 14:11:27 +00:00
|
|
|
return;
|
|
|
|
}
|
2017-12-16 13:01:58 +00:00
|
|
|
|
2017-12-17 14:11:27 +00:00
|
|
|
int blockNumber = mDisasTextEdit->textCursor().blockNumber();
|
2017-12-16 13:01:58 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (blockNumber == blockCount - 1 && !up) {
|
2017-12-17 14:11:27 +00:00
|
|
|
scrollInstructions(1);
|
2018-03-21 20:32:32 +00:00
|
|
|
} else if (blockNumber == 0 && up) {
|
2017-12-17 14:11:27 +00:00
|
|
|
scrollInstructions(-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
mDisasTextEdit->moveCursor(up ? QTextCursor::Up : QTextCursor::Down);
|
|
|
|
|
|
|
|
// handle cases where top instruction offsets change
|
|
|
|
RVA offset = readCurrentDisassemblyOffset();
|
2018-05-25 14:30:59 +00:00
|
|
|
if (offset != seekable->getOffset()) {
|
|
|
|
seekable->seek(offset);
|
2017-12-17 14:11:27 +00:00
|
|
|
highlightCurrentLine();
|
|
|
|
}
|
2017-12-16 13:01:58 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-12 19:55:15 +00:00
|
|
|
bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event)
|
2017-10-11 21:07:32 +00:00
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if ((obj == mDisasTextEdit || obj == mDisasTextEdit->viewport())
|
|
|
|
&& event->type() == QEvent::MouseButtonDblClick) {
|
2017-10-11 21:07:32 +00:00
|
|
|
QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
|
2017-11-28 11:56:38 +00:00
|
|
|
|
2017-10-11 21:07:32 +00:00
|
|
|
QTextCursor cursor = mDisasTextEdit->cursorForPosition(QPoint(mouseEvent->x(), mouseEvent->y()));
|
2017-11-28 11:56:38 +00:00
|
|
|
RVA offset = readDisassemblyOffset(cursor);
|
|
|
|
|
|
|
|
RVA jump = Core()->getOffsetJump(offset);
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (jump == RVA_INVALID) {
|
2017-11-28 11:56:38 +00:00
|
|
|
bool ok;
|
2018-03-21 20:32:32 +00:00
|
|
|
RVA xref = Core()->cmdj("axfj@" + QString::number(
|
|
|
|
offset)).array().first().toObject().value("to").toVariant().toULongLong(&ok);
|
|
|
|
if (ok) {
|
2017-11-28 11:56:38 +00:00
|
|
|
jump = xref;
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
|
|
|
}
|
2017-11-28 11:56:38 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (jump != RVA_INVALID) {
|
2018-05-25 14:30:59 +00:00
|
|
|
seekable->seek(jump);
|
2017-11-28 11:56:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
|
|
|
return QDockWidget::eventFilter(obj, event);
|
|
|
|
}
|
|
|
|
|
2017-10-12 19:55:15 +00:00
|
|
|
void DisassemblyWidget::on_seekChanged(RVA offset)
|
2017-10-11 21:07:32 +00:00
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!seekFromCursor) {
|
2017-12-16 13:01:58 +00:00
|
|
|
cursorLineOffset = 0;
|
|
|
|
}
|
|
|
|
|
2018-04-15 17:06:05 +00:00
|
|
|
if (topOffset != RVA_INVALID
|
2018-03-21 20:32:32 +00:00
|
|
|
&& offset >= topOffset && offset <= bottomOffset) {
|
2017-11-02 06:48:32 +00:00
|
|
|
// if the line with the seek offset is currently visible, just move the cursor there
|
|
|
|
updateCursorPosition();
|
2018-03-21 20:32:32 +00:00
|
|
|
} else {
|
2017-11-02 06:48:32 +00:00
|
|
|
// otherwise scroll there
|
|
|
|
refreshDisasm(offset);
|
|
|
|
}
|
2017-11-03 11:31:20 +00:00
|
|
|
mCtxMenu->setOffset(offset);
|
2017-10-11 21:07:32 +00:00
|
|
|
}
|
2017-10-14 09:35:49 +00:00
|
|
|
|
2017-11-04 11:46:29 +00:00
|
|
|
void DisassemblyWidget::raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type)
|
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (type == CutterCore::MemoryWidgetType::Disassembly) {
|
2017-11-04 11:46:29 +00:00
|
|
|
raise();
|
|
|
|
setFocus();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-14 09:35:49 +00:00
|
|
|
void DisassemblyWidget::fontsUpdatedSlot()
|
|
|
|
{
|
2017-11-30 14:00:22 +00:00
|
|
|
setupFonts();
|
2017-11-20 10:04:03 +00:00
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!updateMaxLines()) { // updateMaxLines() returns true if it already refreshed.
|
2017-11-20 10:04:03 +00:00
|
|
|
refreshDisasm();
|
|
|
|
}
|
2017-10-14 09:35:49 +00:00
|
|
|
}
|
2017-10-16 19:00:47 +00:00
|
|
|
|
2017-11-20 11:23:37 +00:00
|
|
|
void DisassemblyWidget::colorsUpdatedSlot()
|
|
|
|
{
|
2017-11-30 14:00:22 +00:00
|
|
|
setupColors();
|
2017-11-20 11:23:37 +00:00
|
|
|
refreshDisasm();
|
|
|
|
}
|
|
|
|
|
2017-11-30 14:00:22 +00:00
|
|
|
void DisassemblyWidget::setupFonts()
|
|
|
|
{
|
|
|
|
mDisasTextEdit->setFont(Config()->getFont());
|
|
|
|
}
|
|
|
|
|
2017-12-16 13:01:58 +00:00
|
|
|
|
2017-11-30 14:00:22 +00:00
|
|
|
void DisassemblyWidget::setupColors()
|
|
|
|
{
|
|
|
|
mDisasTextEdit->setStyleSheet(QString("QPlainTextEdit { background-color: %1; color: %2; }")
|
2018-03-21 20:32:32 +00:00
|
|
|
.arg(ConfigColor("gui.background").name())
|
|
|
|
.arg(ConfigColor("btext").name()));
|
2017-11-30 14:00:22 +00:00
|
|
|
}
|
|
|
|
|
2017-11-02 06:48:32 +00:00
|
|
|
DisassemblyScrollArea::DisassemblyScrollArea(QWidget *parent) : QAbstractScrollArea(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DisassemblyScrollArea::viewportEvent(QEvent *event)
|
|
|
|
{
|
|
|
|
int dy = verticalScrollBar()->value() - 5;
|
2018-03-21 20:32:32 +00:00
|
|
|
if (dy != 0) {
|
2017-11-02 06:48:32 +00:00
|
|
|
emit scrollLines(dy);
|
|
|
|
}
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (event->type() == QEvent::Resize) {
|
2017-11-02 06:48:32 +00:00
|
|
|
emit disassemblyResized();
|
|
|
|
}
|
|
|
|
|
|
|
|
resetScrollBars();
|
|
|
|
return QAbstractScrollArea::viewportEvent(event);
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisassemblyScrollArea::resetScrollBars()
|
|
|
|
{
|
|
|
|
verticalScrollBar()->blockSignals(true);
|
|
|
|
verticalScrollBar()->setRange(0, 10);
|
|
|
|
verticalScrollBar()->setValue(5);
|
|
|
|
verticalScrollBar()->blockSignals(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool DisassemblyTextEdit::viewportEvent(QEvent *event)
|
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
switch (event->type()) {
|
|
|
|
case QEvent::Type::Wheel:
|
|
|
|
return false;
|
|
|
|
default:
|
|
|
|
return QAbstractScrollArea::viewportEvent(event);
|
2017-11-02 06:48:32 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void DisassemblyTextEdit::scrollContentsBy(int dx, int dy)
|
|
|
|
{
|
2018-03-21 20:32:32 +00:00
|
|
|
if (!lockScroll) {
|
2017-11-02 06:48:32 +00:00
|
|
|
QPlainTextEdit::scrollContentsBy(dx, dy);
|
|
|
|
}
|
|
|
|
}
|
2017-11-04 11:46:29 +00:00
|
|
|
|
2017-11-19 17:49:29 +00:00
|
|
|
void DisassemblyTextEdit::keyPressEvent(QKeyEvent */*event*/)
|
2017-11-04 11:46:29 +00:00
|
|
|
{
|
|
|
|
//QPlainTextEdit::keyPressEvent(event);
|
|
|
|
}
|
2017-11-28 15:42:40 +00:00
|
|
|
|
2017-12-02 13:10:15 +00:00
|
|
|
void DisassemblyTextEdit::mousePressEvent(QMouseEvent *event)
|
|
|
|
{
|
|
|
|
QPlainTextEdit::mousePressEvent(event);
|
|
|
|
|
2018-03-21 20:32:32 +00:00
|
|
|
if (event->button() == Qt::RightButton && !textCursor().hasSelection()) {
|
2017-12-02 13:10:15 +00:00
|
|
|
setTextCursor(cursorForPosition(event->pos()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-11-28 15:42:40 +00:00
|
|
|
void DisassemblyWidget::seekPrev()
|
|
|
|
{
|
|
|
|
Core()->seekPrev();
|
|
|
|
}
|