3434#include < QtCore/QCoreApplication>
3535#include < QtCore/QProcess>
3636
37+ bool SeerEditorWidgetSourceArea::_ctrlHeld = false ;
38+ QTimer* SeerEditorWidgetSourceArea::_ctrlHeldTimer = new QTimer();
39+
3740SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea (QWidget* parent) : SeerPlainTextEdit(parent) {
3841
3942 _fileWatcher = 0 ;
@@ -64,6 +67,11 @@ SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea(QWidget* parent) : SeerPl
6467 enableLineNumberArea (true );
6568 enableBreakPointArea (true );
6669
70+ _ctrlHeldTimer->setInterval (40 ); // 40 ms interval = 25Hz update rate
71+ QObject::connect (_ctrlHeldTimer, &QTimer::timeout, this , [this ]() {
72+ updateCursor (QCursor::pos ());
73+ });
74+
6775 QObject::connect (this , &SeerEditorWidgetSourceArea::blockCountChanged, this , &SeerEditorWidgetSourceArea::updateMarginAreasWidth);
6876 QObject::connect (this , &SeerEditorWidgetSourceArea::updateRequest, this , &SeerEditorWidgetSourceArea::updateLineNumberArea);
6977 QObject::connect (this , &SeerEditorWidgetSourceArea::updateRequest, this , &SeerEditorWidgetSourceArea::updateBreakPointArea);
@@ -83,6 +91,8 @@ SeerEditorWidgetSourceArea::SeerEditorWidgetSourceArea(QWidget* parent) : SeerPl
8391 _lineNumberArea->installEventFilter (lineNumberAreaWheelForwarder);
8492 _breakPointArea->installEventFilter (breakPointAreaWheelForwarder);
8593
94+ _ctrlHeldTimer->start ();
95+
8696 // Calling close() will clear the text document.
8797 close ();
8898}
@@ -2066,6 +2076,16 @@ void SeerEditorWidgetSourceArea::mousePressEvent(QMouseEvent *event)
20662076 }
20672077 } );
20682078 }
2079+ // This part is for Go to definition (Ctrl + Click) feature
2080+ if (event->button () == Qt::LeftButton && _ctrlHeld) {
2081+ if (_wordUnderCursor != " " )
2082+ {
2083+ QApplication::restoreOverrideCursor ();
2084+ signalGotoDefinition (_wordUnderCursor);
2085+ event->ignore (); // If we don't ignore the event, the cursor will move to that position, which is not desired
2086+ return ;
2087+ }
2088+ }
20692089 QPlainTextEdit::mousePressEvent (event);
20702090}
20712091
@@ -2089,8 +2109,72 @@ void SeerEditorWidgetSourceArea::handleCursorPositionChanged()
20892109}
20902110
20912111/* **********************************************************************************************************************
2092- * Go to definition (F12) feature *
2112+ * Go to definition (F12) feature *
20932113 **********************************************************************************************************************/
2114+ void SeerEditorWidgetSourceArea::keyPressEvent (QKeyEvent *event)
2115+ {
2116+ if (event->key () == Qt::Key_Control)
2117+ {
2118+ _ctrlHeld = true ;
2119+ }
2120+ QPlainTextEdit::keyPressEvent (event);
2121+ }
2122+
2123+ void SeerEditorWidgetSourceArea::keyReleaseEvent (QKeyEvent *event)
2124+ {
2125+ if (event->key () == Qt::Key_Control)
2126+ {
2127+ _ctrlHeld = false ;
2128+ }
2129+ QPlainTextEdit::keyReleaseEvent (event);
2130+ }
2131+
2132+ bool SeerEditorWidgetSourceArea::isOverWord (const QPoint &pos)
2133+ {
2134+ QTextCursor cursor = cursorForPosition (pos);
2135+ cursor.select (QTextCursor::WordUnderCursor);
2136+ return !cursor.selectedText ().isEmpty ();
2137+ }
2138+
2139+ QString SeerEditorWidgetSourceArea::wordUnderCursor (const QPoint &pos) const
2140+ {
2141+ int leftMarginOffset = 0 ;
2142+ QMargins margins = viewportMargins ();
2143+ QPoint adjustedPos = pos;
2144+
2145+ // The correct position to get the word under cursor should subtract the left margin
2146+ // offset (breakpoint area and line number area)
2147+ leftMarginOffset = margins.left ();
2148+ adjustedPos.setX (pos.x () - leftMarginOffset);
2149+ QTextCursor cursor = cursorForPosition (adjustedPos);
2150+ cursor.select (QTextCursor::WordUnderCursor);
2151+ return cursor.selectedText ();
2152+ }
2153+
2154+ void SeerEditorWidgetSourceArea::updateCursor (const QPoint &pos)
2155+ {
2156+ // Why not QApplication::setOverrideCursor()? Because QApplication::setOverrideCursor uses internal stack
2157+ // It causes delay and sometimes the cursor won't change back to normal when we want it to.
2158+ // In short, QApplication::setOverrideCursor is global and not real time
2159+ // In contrary, viewport()->setCursor() is local and real time, apply only for that widget, in this case, the text area
2160+ QPoint localPos = mapFromGlobal (pos);
2161+ if (!_ctrlHeld) {
2162+ viewport ()->setCursor (Qt::IBeamCursor);
2163+ _wordUnderCursor = " " ;
2164+ return ;
2165+ }
2166+ if (!hasFocus ())
2167+ return ;
2168+ _wordUnderCursor = wordUnderCursor (localPos);
2169+ if (isValidIdentifier (_wordUnderCursor))
2170+ {
2171+ viewport ()->setCursor (Qt::PointingHandCursor);
2172+ } else {
2173+ viewport ()->setCursor (Qt::IBeamCursor);
2174+ _wordUnderCursor = " " ;
2175+ }
2176+ }
2177+
20942178// Check text and decide if that text is valid identifier (function, variable, type name)
20952179bool SeerEditorWidgetSourceArea::isValidIdentifier (const QString& text)
20962180{
0 commit comments