diff --git a/src/widgets/DisassemblyWidget.cpp b/src/widgets/DisassemblyWidget.cpp index 946a2d35..bbeef00e 100644 --- a/src/widgets/DisassemblyWidget.cpp +++ b/src/widgets/DisassemblyWidget.cpp @@ -439,6 +439,29 @@ void DisassemblyWidget::highlightPCLine() mDisasTextEdit->setExtraSelections(currentSelections); } +void DisassemblyWidget::highlightMultiLineSelections() +{ + QList extraSelections; + QTextEdit::ExtraSelection highlightSelection; + QColor highlightColor = ConfigColor("lineHighlight"); + + // Highlight each selection in the multilineSelections list + for (const QTextEdit::ExtraSelection &selection : mDisasTextEdit->getMultiLineSelections()) { + highlightSelection.format.setBackground(highlightColor); + highlightSelection.format.setProperty(QTextFormat::FullWidthSelection, true); + highlightSelection.cursor = mDisasTextEdit->textCursor(); + highlightSelection.cursor.setPosition(selection.cursor.selectionStart()); + highlightSelection.cursor.setPosition(selection.cursor.selectionEnd(), + QTextCursor::KeepAnchor); + extraSelections.append(highlightSelection); + } + + // Don't override any extraSelections already set + QList currentSelections = mDisasTextEdit->extraSelections(); + currentSelections.append(extraSelections); + mDisasTextEdit->setExtraSelections(currentSelections); +} + void DisassemblyWidget::showDisasContextMenu(const QPoint &pt) { mCtxMenu->exec(mDisasTextEdit->mapToGlobal(pt)); @@ -511,7 +534,7 @@ void DisassemblyWidget::updateCursorPosition() } highlightPCLine(); - + highlightMultiLineSelections(); connectCursorPositionChanged(false); } @@ -546,6 +569,7 @@ void DisassemblyWidget::cursorPositionChanged() seekFromCursor = false; highlightCurrentLine(); highlightPCLine(); + highlightMultiLineSelections(); mCtxMenu->setCanCopy(mDisasTextEdit->textCursor().hasSelection()); if (mDisasTextEdit->textCursor().hasSelection()) { // A word is selected so use it @@ -615,6 +639,7 @@ void DisassemblyWidget::moveCursorRelative(bool up, bool page) seekable->seek(offset); highlightCurrentLine(); highlightPCLine(); + highlightMultiLineSelections(); } } } @@ -661,7 +686,10 @@ bool DisassemblyWidget::eventFilter(QObject *obj, QEvent *event) void DisassemblyWidget::keyPressEvent(QKeyEvent *event) { - if (event->key() == Qt::Key_Return) { + if (event->key() == Qt::Key_Shift) { + qDebug() << "shift key pressed"; + mDisasTextEdit->setMultiLineSelection(true); + } else if (event->key() == Qt::Key_Return) { const QTextCursor cursor = mDisasTextEdit->textCursor(); jumpToOffsetUnderCursor(cursor); } @@ -669,6 +697,16 @@ void DisassemblyWidget::keyPressEvent(QKeyEvent *event) MemoryDockWidget::keyPressEvent(event); } +void DisassemblyWidget::keyReleaseEvent(QKeyEvent *event) +{ + if (event->key() == Qt::Key_Shift) { + qDebug() << "shift key released"; + mDisasTextEdit->setMultiLineSelection(false); + } + + MemoryDockWidget::keyReleaseEvent(event); +} + QString DisassemblyWidget::getWindowTitle() const { return tr("Disassembly"); @@ -788,9 +826,64 @@ void DisassemblyTextEdit::keyPressEvent(QKeyEvent *event) Q_UNUSED(event) // QPlainTextEdit::keyPressEvent(event); } - void DisassemblyTextEdit::mousePressEvent(QMouseEvent *event) { + if (event->button() == Qt::LeftButton && !multiLineSelection) { + multilineSelections.clear(); + } + + // Check for left button click and multiline individual selection mode (shift key pressed) + if (event->button() == Qt::LeftButton && multiLineSelection) { + // Use cursorForPosition to set the cursor to the exact click position + QTextCursor cursor = cursorForPosition(event->pos()); + setTextCursor(cursor); // Update the text cursor to this position + + int startPos = cursor.selectionStart(); + int endPos = cursor.selectionEnd(); + + // Format selection + QTextEdit::ExtraSelection selection; + selection.format.setBackground(QColor("green")); + selection.format.setProperty(QTextFormat::FullWidthSelection, true); + + // Move cursor to start of the line + cursor.movePosition(QTextCursor::StartOfLine); + startPos = cursor.position(); + + // Extend cursor to the end of the line + cursor.movePosition(QTextCursor::EndOfLine, QTextCursor::KeepAnchor); + endPos = cursor.position(); + + // Debug log + qDebug() << "Offset of line added: " << startPos << "-" << endPos; + + // Check if line is already selected + auto it = std::find_if(multilineSelections.begin(), multilineSelections.end(), + [startPos, endPos](const QTextEdit::ExtraSelection &s) { + return s.cursor.selectionStart() == startPos + && s.cursor.selectionEnd() == endPos; + }); + + if (it != multilineSelections.end()) { + // Deselect if already selected + multilineSelections.erase(it); + } else { + // Add this line to the selections if not already selected + selection.cursor = cursor; + multilineSelections.append(selection); + } + + // Apply the selections + setExtraSelections(multilineSelections); + + // Debug log + qDebug() << "Multiline selections:"; + for (const auto &selection : multilineSelections) { + qDebug() << "Start:" << selection.cursor.selectionStart() + << "End:" << selection.cursor.selectionEnd(); + } + } + QPlainTextEdit::mousePressEvent(event); if (event->button() == Qt::RightButton && !textCursor().hasSelection()) { @@ -1027,4 +1120,4 @@ void DisassemblyLeftPanel::clearArrowFrom(RVA offset) if (it != arrows.end()) { arrows.erase(it); } -} +} \ No newline at end of file diff --git a/src/widgets/DisassemblyWidget.h b/src/widgets/DisassemblyWidget.h index 8dadd4d4..7074323c 100644 --- a/src/widgets/DisassemblyWidget.h +++ b/src/widgets/DisassemblyWidget.h @@ -41,6 +41,7 @@ public slots: * overrides all previous highlighting. */ void highlightPCLine(); + void highlightMultiLineSelections(); void showDisasContextMenu(const QPoint &pt); void fontsUpdatedSlot(); void colorsUpdatedSlot(); @@ -86,6 +87,7 @@ private: RVA readCurrentDisassemblyOffset(); bool eventFilter(QObject *obj, QEvent *event) override; void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; QString getWindowTitle() const override; int topOffsetHistoryPos = 0; @@ -129,11 +131,16 @@ class DisassemblyTextEdit : public QPlainTextEdit public: explicit DisassemblyTextEdit(QWidget *parent = nullptr) - : QPlainTextEdit(parent), lockScroll(false) + : QPlainTextEdit(parent), lockScroll(false), multiLineSelection(false) { } void setLockScroll(bool lock) { this->lockScroll = lock; } + void setMultiLineSelection(bool multiLineSelection) { this->multiLineSelection = multiLineSelection; } + void setMultiLineSelections(const QList &selections) { multilineSelections = selections; } + + bool getMultiLineSelection() const { return multiLineSelection; } + QList getMultiLineSelections() const { return multilineSelections; } qreal textOffset() const; @@ -145,6 +152,8 @@ protected: private: bool lockScroll; + bool multiLineSelection; + QList multilineSelections; }; /** @@ -197,4 +206,4 @@ private: std::vector arrows; }; -#endif // DISASSEMBLYWIDGET_H +#endif // DISASSEMBLYWIDGET_H \ No newline at end of file