mirror of
https://github.com/rizinorg/cutter.git
synced 2025-02-22 14:43:46 +00:00
Cursor Key Navigation in DisassemblyContextWidget #167
This commit is contained in:
parent
a3cc04fb2d
commit
4613ffa485
@ -409,7 +409,7 @@ RVA CutterCore::nextOpAddr(RVA startAddr, int count)
|
|||||||
{
|
{
|
||||||
CORE_LOCK();
|
CORE_LOCK();
|
||||||
|
|
||||||
QJsonArray array = Core()->cmdj("pdj " + QString::number(count) + "@" + QString::number(startAddr)).array();
|
QJsonArray array = Core()->cmdj("pdj " + QString::number(count+1) + "@" + QString::number(startAddr)).array();
|
||||||
if (array.isEmpty())
|
if (array.isEmpty())
|
||||||
{
|
{
|
||||||
return startAddr + 1;
|
return startAddr + 1;
|
||||||
|
@ -25,6 +25,17 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static DisassemblyTextBlockUserData *getUserData(const QTextBlock &block)
|
||||||
|
{
|
||||||
|
QTextBlockUserData *userData = block.userData();
|
||||||
|
if (!userData)
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return static_cast<DisassemblyTextBlockUserData *>(userData);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
DisassemblyWidget::DisassemblyWidget(QWidget *parent)
|
DisassemblyWidget::DisassemblyWidget(QWidget *parent)
|
||||||
: QDockWidget(parent)
|
: QDockWidget(parent)
|
||||||
@ -33,6 +44,8 @@ DisassemblyWidget::DisassemblyWidget(QWidget *parent)
|
|||||||
, mDisasTextEdit(new DisassemblyTextEdit(this))
|
, mDisasTextEdit(new DisassemblyTextEdit(this))
|
||||||
{
|
{
|
||||||
topOffset = bottomOffset = RVA_INVALID;
|
topOffset = bottomOffset = RVA_INVALID;
|
||||||
|
cursorLineOffset = 0;
|
||||||
|
seekFromCursor = false;
|
||||||
|
|
||||||
QVBoxLayout *layout = new QVBoxLayout();
|
QVBoxLayout *layout = new QVBoxLayout();
|
||||||
layout->addWidget(mDisasTextEdit);
|
layout->addWidget(mDisasTextEdit);
|
||||||
@ -126,6 +139,18 @@ DisassemblyWidget::DisassemblyWidget(QWidget *parent)
|
|||||||
QShortcut *shortcut_escape = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
QShortcut *shortcut_escape = new QShortcut(QKeySequence(Qt::Key_Escape), this);
|
||||||
shortcut_escape->setContext(Qt::WidgetShortcut);
|
shortcut_escape->setContext(Qt::WidgetShortcut);
|
||||||
connect(shortcut_escape, SIGNAL(activated()), this, SLOT(seekPrev()));
|
connect(shortcut_escape, SIGNAL(activated()), this, SLOT(seekPrev()));
|
||||||
|
|
||||||
|
|
||||||
|
#define ADD_SHORTCUT(ksq, slot) { \
|
||||||
|
QShortcut *s = new QShortcut((ksq), this); \
|
||||||
|
s->setContext(Qt::WidgetShortcut); \
|
||||||
|
connect(s, &QShortcut::activated, this, (slot)); \
|
||||||
|
}
|
||||||
|
ADD_SHORTCUT(QKeySequence::MoveToNextLine, [this]() { moveCursorRelative(false, 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); })
|
||||||
|
#undef ADD_SHORTCUT
|
||||||
}
|
}
|
||||||
|
|
||||||
DisassemblyWidget::DisassemblyWidget(const QString &title, QWidget *parent) :
|
DisassemblyWidget::DisassemblyWidget(const QString &title, QWidget *parent) :
|
||||||
@ -315,14 +340,13 @@ RVA DisassemblyWidget::readCurrentDisassemblyOffset()
|
|||||||
|
|
||||||
RVA DisassemblyWidget::readDisassemblyOffset(QTextCursor tc)
|
RVA DisassemblyWidget::readDisassemblyOffset(QTextCursor tc)
|
||||||
{
|
{
|
||||||
QTextBlockUserData *userData = tc.block().userData();
|
auto userData = getUserData(tc.block());
|
||||||
if (!userData)
|
if (!userData)
|
||||||
{
|
{
|
||||||
return RVA_INVALID;
|
return RVA_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *dsUserData = static_cast<DisassemblyTextBlockUserData *>(userData);
|
return userData->line.offset;
|
||||||
return dsUserData->line.offset;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DisassemblyWidget::updateCursorPosition()
|
void DisassemblyWidget::updateCursorPosition()
|
||||||
@ -356,6 +380,11 @@ void DisassemblyWidget::updateCursorPosition()
|
|||||||
RVA lineOffset = readDisassemblyOffset(cursor);
|
RVA lineOffset = readDisassemblyOffset(cursor);
|
||||||
if (lineOffset == offset)
|
if (lineOffset == offset)
|
||||||
{
|
{
|
||||||
|
if (cursorLineOffset > 0)
|
||||||
|
{
|
||||||
|
cursor.movePosition(QTextCursor::Down, QTextCursor::MoveAnchor, cursorLineOffset);
|
||||||
|
}
|
||||||
|
|
||||||
mDisasTextEdit->setTextCursor(cursor);
|
mDisasTextEdit->setTextCursor(cursor);
|
||||||
highlightCurrentLine();
|
highlightCurrentLine();
|
||||||
break;
|
break;
|
||||||
@ -401,11 +430,62 @@ void DisassemblyWidget::connectCursorPositionChanged(bool disconnect)
|
|||||||
void DisassemblyWidget::cursorPositionChanged()
|
void DisassemblyWidget::cursorPositionChanged()
|
||||||
{
|
{
|
||||||
RVA offset = readCurrentDisassemblyOffset();
|
RVA offset = readCurrentDisassemblyOffset();
|
||||||
|
|
||||||
|
cursorLineOffset = 0;
|
||||||
|
QTextCursor c = mDisasTextEdit->textCursor();
|
||||||
|
while (c.blockNumber() > 0)
|
||||||
|
{
|
||||||
|
c.movePosition(QTextCursor::PreviousBlock);
|
||||||
|
if (readDisassemblyOffset(c) != offset)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cursorLineOffset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
seekFromCursor = true;
|
||||||
Core()->seek(offset);
|
Core()->seek(offset);
|
||||||
|
seekFromCursor = false;
|
||||||
highlightCurrentLine();
|
highlightCurrentLine();
|
||||||
mCtxMenu->setCanCopy(mDisasTextEdit->textCursor().hasSelection());
|
mCtxMenu->setCanCopy(mDisasTextEdit->textCursor().hasSelection());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisassemblyWidget::moveCursorRelative(bool up, bool page)
|
||||||
|
{
|
||||||
|
if (page)
|
||||||
|
{
|
||||||
|
// TODO: implement page up/down
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blockCount = mDisasTextEdit->blockCount();
|
||||||
|
if (blockCount < 1)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int blockNumber = mDisasTextEdit->textCursor().blockNumber();
|
||||||
|
|
||||||
|
if (blockNumber == blockCount - 1 && !up)
|
||||||
|
{
|
||||||
|
scrollInstructions(1);
|
||||||
|
}
|
||||||
|
else if (blockNumber == 0 && up)
|
||||||
|
{
|
||||||
|
scrollInstructions(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
mDisasTextEdit->moveCursor(up ? QTextCursor::Up : QTextCursor::Down);
|
||||||
|
|
||||||
|
// handle cases where top instruction offsets change
|
||||||
|
RVA offset = readCurrentDisassemblyOffset();
|
||||||
|
if (offset != Core()->getOffset())
|
||||||
|
{
|
||||||
|
Core()->seek(offset);
|
||||||
|
highlightCurrentLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event)
|
bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event)
|
||||||
{
|
{
|
||||||
if ((obj == mDisasTextEdit || obj == mDisasTextEdit->viewport()) && event->type() == QEvent::MouseButtonDblClick)
|
if ((obj == mDisasTextEdit || obj == mDisasTextEdit->viewport()) && event->type() == QEvent::MouseButtonDblClick)
|
||||||
@ -439,6 +519,11 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event)
|
|||||||
|
|
||||||
void DisassemblyWidget::on_seekChanged(RVA offset)
|
void DisassemblyWidget::on_seekChanged(RVA offset)
|
||||||
{
|
{
|
||||||
|
if (!seekFromCursor)
|
||||||
|
{
|
||||||
|
cursorLineOffset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (topOffset != RVA_INVALID && bottomOffset != RVA_INVALID
|
if (topOffset != RVA_INVALID && bottomOffset != RVA_INVALID
|
||||||
&& offset >= topOffset && offset <= bottomOffset)
|
&& offset >= topOffset && offset <= bottomOffset)
|
||||||
{
|
{
|
||||||
@ -483,6 +568,7 @@ void DisassemblyWidget::setupFonts()
|
|||||||
mDisasTextEdit->setFont(Config()->getFont());
|
mDisasTextEdit->setFont(Config()->getFont());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void DisassemblyWidget::setupColors()
|
void DisassemblyWidget::setupColors()
|
||||||
{
|
{
|
||||||
mDisasTextEdit->setStyleSheet(QString("QPlainTextEdit { background-color: %1; color: %2; }")
|
mDisasTextEdit->setStyleSheet(QString("QPlainTextEdit { background-color: %1; color: %2; }")
|
||||||
@ -490,7 +576,6 @@ void DisassemblyWidget::setupColors()
|
|||||||
.arg(ConfigColor("btext").name()));
|
.arg(ConfigColor("btext").name()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
DisassemblyScrollArea::DisassemblyScrollArea(QWidget *parent) : QAbstractScrollArea(parent)
|
DisassemblyScrollArea::DisassemblyScrollArea(QWidget *parent) : QAbstractScrollArea(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,12 @@ private:
|
|||||||
RVA bottomOffset;
|
RVA bottomOffset;
|
||||||
int maxLines;
|
int maxLines;
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* offset of lines below the first line of the current seek
|
||||||
|
*/
|
||||||
|
int cursorLineOffset;
|
||||||
|
bool seekFromCursor;
|
||||||
|
|
||||||
RVA readCurrentDisassemblyOffset();
|
RVA readCurrentDisassemblyOffset();
|
||||||
RVA readDisassemblyOffset(QTextCursor tc);
|
RVA readDisassemblyOffset(QTextCursor tc);
|
||||||
bool eventFilter(QObject *obj, QEvent *event);
|
bool eventFilter(QObject *obj, QEvent *event);
|
||||||
@ -56,6 +62,8 @@ private:
|
|||||||
void updateCursorPosition();
|
void updateCursorPosition();
|
||||||
|
|
||||||
void connectCursorPositionChanged(bool disconnect);
|
void connectCursorPositionChanged(bool disconnect);
|
||||||
|
|
||||||
|
void moveCursorRelative(bool up, bool page);
|
||||||
};
|
};
|
||||||
|
|
||||||
class DisassemblyScrollArea : public QAbstractScrollArea
|
class DisassemblyScrollArea : public QAbstractScrollArea
|
||||||
|
Loading…
Reference in New Issue
Block a user