Add feature: Mouse navigation

This commit is contained in:
QuangNguyenMinh123
2026-01-21 22:09:17 +07:00
parent 77baafacba
commit 855fce6c33
4 changed files with 167 additions and 1 deletions
+111 -1
View File
@@ -902,6 +902,8 @@ void SeerEditorManagerWidget::handleOpenFileWithDetails (const QString& file, co
}
}
handleAddToMouseNavigation({file, fullname, cursorRow, 1, editorWidget->sourceArea()->firstDisplayLine()});
// Ask for the breakpoint list to be resent, in case this file has breakpoints.
emit refreshBreakpointsList();
@@ -1035,6 +1037,7 @@ SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QS
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer);
QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation);
// Send the Editor widget the command to load the file. ??? Do better than this.
editorWidget->sourceArea()->handleText(text);
@@ -1097,6 +1100,7 @@ SeerEditorWidgetSource* SeerEditorManagerWidget::createEditorWidgetTab (const QS
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addMatrixVisualizer, this, &SeerEditorManagerWidget::handleAddMatrixVisualizer);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addStructVisualizer, this, &SeerEditorManagerWidget::handleAddStructVisualizer);
QObject::connect(editorWidget, &SeerEditorWidgetSource::addAlternateDirectory, this, &SeerEditorManagerWidget::handleAddAlternateDirectory);
QObject::connect(editorWidget->sourceArea(), &SeerEditorWidgetSourceArea::addToMouseNavigation, this, &SeerEditorManagerWidget::handleAddToMouseNavigation);
// Load the file.
editorWidget->sourceArea()->open(fullname, QFileInfo(file).fileName());
@@ -1475,10 +1479,116 @@ void SeerEditorManagerWidget::handleSessionTerminated () {
}
}
// Clear the stack of recently closed files whenever a new gdb session starts
// Clear the stack of recently closed files backward/forward list whenever a new gdb session starts
void SeerEditorManagerWidget::handleGdbStateChanged()
{
while (!_stackClosedFiles.empty()) {
_stackClosedFiles.pop();
}
_listForwardFiles.clear();
_forwardFilesIndex = -1;
}
/***********************************************************************************************************************
* Function for handling mouse navigation
**********************************************************************************************************************/
void SeerEditorManagerWidget::handleAddToMouseNavigation(const SeerEditorWidgetSourceArea::SeerCurrentFile& currentFile)
{
// Record this file in the forward list.
if (currentFile.file != "")
{
// Check if the last added file is the same as currentFile
if (!_listForwardFiles.empty())
{
const SeerEditorWidgetSourceArea::SeerCurrentFile& lastFile = _listForwardFiles[_listForwardFiles.size() -1];
if (currentFile == lastFile)
{
return;
}
}
// if _forwardFilesIndex is at the end of the list, just append
if (_forwardFilesIndex >= _listForwardFiles.size() - 1)
{
_listForwardFiles.append(currentFile);
_forwardFilesIndex ++;
}
else // else remove all entries after _forwardFilesIndex and then append
{
int removeCount = _listForwardFiles.size() - 1 - _forwardFilesIndex;
if ((currentFile == _listForwardFiles[_listForwardFiles.size() -1]) || (currentFile == _listForwardFiles[0])
|| (currentFile == _listForwardFiles[_listForwardFiles.size() - 1 - removeCount]) )
{
return;
}
for (int i=0; i < removeCount; i++)
{
_listForwardFiles.removeLast();
}
_listForwardFiles.append(currentFile);
_forwardFilesIndex = _listForwardFiles.size() -1;
}
}
}
void SeerEditorManagerWidget::handleOpenForwardBackward(const SeerEditorWidgetSourceArea::SeerCurrentFile& fileInfo) {
// Get the EditorWidget for the file. Create one if needed.
SeerEditorWidgetSource* editorWidget = editorWidgetTab(fileInfo.fullname);
if (editorWidget == 0) {
editorWidget = createEditorWidgetTab(fileInfo.fullname, fileInfo.file);
}
// Can still be null, if the file is ignored.
if (editorWidget == 0) {
return;
}
// Push this tab to the top only if the current one in not the "Assembly" tab.
QString tabtext = "";
if (tabWidget->currentIndex() >= 0) {
tabtext = tabWidget->tabText(tabWidget->currentIndex());
}
if (keepAssemblyTabOnTop() && tabtext == "Assembly") {
// Do nothing. The "Assembly" tab is already on top.
}else{
tabWidget->setCurrentWidget(editorWidget);
}
if (fileInfo.firstDisplayLine > 0) { // scroll to the previous first display line
QScrollBar *scrollBar = editorWidget->sourceArea()->verticalScrollBar();
int step = scrollBar->singleStep();
scrollBar->setValue(fileInfo.firstDisplayLine * step - 1);
// Set cursor position
QTextBlock block = editorWidget->sourceArea()->document()->findBlockByLineNumber(fileInfo.cursorRow-1);
QTextCursor cursor = editorWidget->sourceArea()->textCursor();
cursor.setPosition(block.position() + fileInfo.cursorCol - 1);
editorWidget->sourceArea()->setTextCursor(cursor);
}
}
// Handle mouse press events for navigation
void SeerEditorManagerWidget::mousePressEvent(QMouseEvent *event)
{
// Back button (XButton1) clicked
if (event->button() == Qt::XButton1) {
if (_forwardFilesIndex - 1 < 0)
return;
--_forwardFilesIndex;
const SeerEditorWidgetSourceArea::SeerCurrentFile &info = _listForwardFiles.at(_forwardFilesIndex);
handleOpenForwardBackward(info);
}
// Forward button (XButton2) clicked
else if (event->button() == Qt::XButton2) {
if (_forwardFilesIndex + 1 > _listForwardFiles.size() - 1)
return;
++ _forwardFilesIndex;
const SeerEditorWidgetSourceArea::SeerCurrentFile &info = _listForwardFiles.at(_forwardFilesIndex);
handleOpenForwardBackward(info);
}
else
{
QWidget::mousePressEvent(event);
}
}
+8
View File
@@ -103,6 +103,10 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
void handleAssemblyConfigChanged ();
void handleSessionTerminated ();
void handleGdbStateChanged ();
void handleAddToMouseNavigation (const SeerEditorWidgetSourceArea::SeerCurrentFile& currentFile);
protected:
void mousePressEvent (QMouseEvent *event) override;
private slots:
void handleFileOpenToolButtonClicked ();
@@ -144,6 +148,7 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
SeerEditorWidgetAssembly* createAssemblyWidgetTab ();
void deleteAssemblyWidgetTab ();
void handleOpenFileWithDetails (const QString& file, const QString& fullname, int cursorRow, int cursorCol, int firstDisplayLine);
void handleOpenForwardBackward (const SeerEditorWidgetSourceArea::SeerCurrentFile& fileInfo);
SeerEditorManagerEntries _entries;
SeerHighlighterSettings _editorHighlighterSettings;
@@ -167,5 +172,8 @@ class SeerEditorManagerWidget : public QWidget, protected Ui::SeerEditorManagerW
// list of recently closed files (Ctrl + Shift + T)
QStack<SeerEditorWidgetSourceArea::SeerCurrentFile> _stackClosedFiles;
// list of cursor positions for mouse navigation (back/forward)
QList<SeerEditorWidgetSourceArea::SeerCurrentFile> _listForwardFiles;
int _forwardFilesIndex = -1;
};
+5
View File
@@ -140,6 +140,7 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
void showAlternateBar (bool flag);
void showReloadBar (bool flag);
void highlighterSettingsChanged ();
void addToMouseNavigation (const SeerCurrentFile& currentFile);
public slots:
void handleText (const QString& text);
@@ -154,6 +155,7 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
bool event (QEvent* event);
void showExpressionTooltip ();
void hideExpressionTooltip ();
void mousePressEvent (QMouseEvent *event) override;
private slots:
void refreshExtraSelections ();
@@ -163,6 +165,7 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
void updateBreakPointArea (const QRect& rect, int dy);
private:
void handleCursorPositionChanged ();
QString _fullname;
QString _file;
QString _alternateDirectory;
@@ -194,6 +197,8 @@ class SeerEditorWidgetSourceArea : public SeerPlainTextEdit {
int _sourceTabSize;
QString _externalEditorCommand;
int _ignoreThumbMouseEvent = 0;
};
class SeerEditorWidgetSourceLineNumberArea : public QWidget {
+43
View File
@@ -69,6 +69,9 @@ SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea(QWidget* parent) : SeerPl
QObject::connect(this, &SeerEditorWidgetSourceArea::updateRequest, this, &SeerEditorWidgetSourceArea::updateBreakPointArea);
QObject::connect(this, &SeerEditorWidgetSourceArea::highlighterSettingsChanged, this, &SeerEditorWidgetSourceArea::handleHighlighterSettingsChanged);
// Connect cursor position changed signal.
QObject::connect(this, &QPlainTextEdit::cursorPositionChanged, this, &SeerEditorWidgetSourceArea::handleCursorPositionChanged);
setCurrentLine(0);
updateMarginAreasWidth(0);
@@ -2025,3 +2028,43 @@ void SeerEditorWidgetSourceBreakPointArea::mouseReleaseEvent (QMouseEvent* event
QWidget::mouseReleaseEvent(event);
}
/***********************************************************************************************************************
* Functions for mouse navigation feature *
**********************************************************************************************************************/
void SeerEditorWidgetSourceArea::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::XButton1 || event->button() == Qt::XButton2) {
// Avoid the default back/forward action
_ignoreThumbMouseEvent ++;
SeerCurrentFile firstInfo = readCurrentPosition();
// _ignoreThumbMouseEvent will incremented in mousePressEvent when thumb mouse button is pressed but it may not be decremented
// if user just click the thumb mouse button without moving the cursor. So here we check if the position is the same as last time,
// which means cursor didn't move, then we reset _ignoreThumbMouseEvent to 0 to avoid blocking future events.
QTimer::singleShot(30, this, [this, firstInfo]() { // let's give 30 ms for cursor to move to new position
SeerCurrentFile secondInfo = readCurrentPosition();
if (firstInfo == secondInfo) { // cursor didn't move
_ignoreThumbMouseEvent = 0; // reset to 0
}
} );
}
QPlainTextEdit::mousePressEvent(event);
}
void SeerEditorWidgetSourceArea::handleCursorPositionChanged()
{
// Emit signal to SeerEditorManagerWidget.cpp and save position
// Read current position, deploy a timer
SeerCurrentFile firstInfo = readCurrentPosition();
if (_ignoreThumbMouseEvent > 0)
{
_ignoreThumbMouseEvent --;
return;
}
QTimer::singleShot(2000, this, [this, firstInfo]() {
SeerCurrentFile secondInfo = readCurrentPosition();
if (firstInfo == secondInfo) {
emit addToMouseNavigation(firstInfo);
}
} );
}