diff --git a/NEWS.md b/NEWS.md index 4aec36a1..58e97808 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +Red Panda C++ Version 2.26 + - enhancement: Code suggestion for embedded std::vectors. + - change: Use ctrl+mouseMove event to highlight jumpable symbols (instead of ctrl+tooltip). + - enhancement: Auto adjust position of the suggestion popup window. + Red Panda C++ Version 2.25 - fix: Symbol completion of '(' before selection may fail, if cursor is at the beginning of the selection. diff --git a/RedPandaIDE/RedPandaIDE.pro b/RedPandaIDE/RedPandaIDE.pro index fc00c080..e2e687b0 100644 --- a/RedPandaIDE/RedPandaIDE.pro +++ b/RedPandaIDE/RedPandaIDE.pro @@ -10,13 +10,12 @@ CONFIG += nokey # uncomment the following line to enable sdcc support CONFIG += ENABLE_SDCC -isEmpty(APP_NAME) { - APP_NAME = RedPandaCPP -} -isEmpty(APP_VERSION) { - APP_VERSION = 2.25 -} +APP_NAME = RedPandaCPP + +APP_VERSION = 2.26 + +TEST_VERSION = alpha1 contains(QMAKE_HOST.arch, x86_64):{ DEFINES += ARCH_X86_64=1 @@ -54,7 +53,11 @@ win32: { DEFINES += PREFIX=\\\"$${PREFIX}\\\" DEFINES += LIBEXECDIR=\\\"$${LIBEXECDIR}\\\" DEFINES += APP_NAME=\\\"$${APP_NAME}\\\" -DEFINES += REDPANDA_CPP_VERSION=\\\"$${APP_VERSION}\\\" +isEmpty(TEST_VERSION) { + DEFINES += REDPANDA_CPP_VERSION=\\\"$${APP_VERSION}\\\" +} else { + DEFINES += REDPANDA_CPP_VERSION=\\\"$${APP_VERSION}-$${TEST_VERSION}\\\" +} gcc { QMAKE_CXXFLAGS_RELEASE += -Werror=return-type diff --git a/RedPandaIDE/editor.cpp b/RedPandaIDE/editor.cpp index 340677ae..a2ded5c5 100644 --- a/RedPandaIDE/editor.cpp +++ b/RedPandaIDE/editor.cpp @@ -48,6 +48,7 @@ #include #include #include +#include #include "iconsmanager.h" #include "debugger.h" #include "editorlist.h" @@ -706,6 +707,22 @@ void Editor::keyPressEvent(QKeyEvent *event) event->accept(); } }); + if (event->modifiers() == Qt::ControlModifier + && event->key() == Qt::Key_Control + && !mCompletionPopup->isVisible() + && !mHeaderCompletionPopup->isVisible() + ) { + setMouseTracking(true); + handled=true; + QMouseEvent mouseEvent{ + QEvent::MouseMove, + mapFromGlobal(QCursor::pos()), + Qt::NoButton, + Qt::NoButton, + Qt::ControlModifier}; + mouseMoveEvent( &mouseEvent ); + return; + } if (readOnly()) return; @@ -1046,6 +1063,40 @@ void Editor::keyPressEvent(QKeyEvent *event) handled = handleCodeCompletion(ch); } +void Editor::keyReleaseEvent(QKeyEvent *event) +{ + if (event->modifiers() == Qt::NoModifier + && event->key() == Qt::Key_Control) { + setMouseTracking(false); + cancelHoverLink(); + updateMouseCursor(); + return; + } + QSynedit::QSynEdit::keyReleaseEvent(event); +} + +void Editor::mouseMoveEvent(QMouseEvent *event) +{ + if(event->modifiers() == Qt::ControlModifier) { + cancelHint(); + + QSynedit::BufferCoord p; + TipType reason = getTipType(event->pos(),p); + if (reason == TipType::Preprocessor) { + QString s = document()->getLine(p.line - 1); + if (mParser->isIncludeNextLine(s) || mParser->isIncludeLine(s)) + updateHoverLink(p.line); + } else if (reason == TipType::Identifier) { + updateHoverLink(p.line); + } else { + cancelHoverLink(); + } + return; + } + + QSynedit::QSynEdit::mouseMoveEvent(event); +} + void Editor::onGutterPaint(QPainter &painter, int aLine, int X, int Y) { IconsManager::PPixmap icon; @@ -1150,18 +1201,13 @@ void Editor::onPreparePaintHighlightToken(int line, int aChar, const QString &to } QString lineText = document()->getLine(line-1); if (mParser->isIncludeLine(lineText)) { - if (cursor() == Qt::PointingHandCursor) { - QSynedit::BufferCoord p; - if (pointToCharLine(mapFromGlobal(QCursor::pos()),p)) { - if (line==p.line){ - int pos1=std::max(lineText.indexOf("<"),lineText.indexOf("\"")); - int pos2=std::max(lineText.lastIndexOf(">"),lineText.lastIndexOf("\"")); - pos1++; - pos2++; - if (pos1>0 && pos2>0 && pos1"),lineText.lastIndexOf("\"")); + pos1++; + pos2++; + if (pos1>0 && pos2>0 && pos1enabled() && attr->tokenType() == QSynedit::TokenType::Identifier) { @@ -1207,7 +1253,7 @@ void Editor::onPreparePaintHighlightToken(int line, int aChar, const QString &to } else { foreground = syntaxer()->identifierAttribute()->foreground(); } - if (cursor() == Qt::PointingHandCursor) { + if (line == mHoverModifiedLine) { QSynedit::BufferCoord p; if (pointToCharLine(mapFromGlobal(QCursor::pos()),p)) { if (line==p.line && (aChar<=p.ch && p.chtype() == QEvent::HoverEnter || event->type() == QEvent::HoverMove) && qApp->mouseButtons() == Qt::NoButton && pSettings->editor().enableTooltips() - && !pMainWindow->completionPopup()->isVisible() + && !mCompletionPopup->isVisible() && !pMainWindow->functionTip()->isVisible() - && !pMainWindow->headerCompletionPopup()->isVisible()) { + && !mHeaderCompletionPopup->isVisible()) { cancelHint(); mTooltipTimer.stop(); if (pSettings->editor().tipsDelay()>0) { @@ -1314,7 +1360,7 @@ void Editor::mouseReleaseEvent(QMouseEvent *event) // if ctrl+clicked if ((event->modifiers() == Qt::ControlModifier) && (event->button() == Qt::LeftButton)) { - if (!selAvail() && !mCurrentWord.isEmpty()) { + if (!selAvail() && mHoverModifiedLine != -1) { QSynedit::BufferCoord p; if (mParser && pointToCharLine(event->pos(),p)) { QString s = document()->getLine(p.line - 1); @@ -1342,7 +1388,7 @@ void Editor::inputMethodEvent(QInputMethodEvent *event) QString s = event->commitString(); if (s.isEmpty()) return; - if (pMainWindow->completionPopup()->isVisible()) { + if (mCompletionPopup->isVisible()) { onCompletionInputMethod(event); return; } else { @@ -1895,10 +1941,8 @@ void Editor::onAutoBackupTimer() void Editor::onTooltipTimer() { - if(mHoverModifiedLine!=-1) { - invalidateLine(mHoverModifiedLine); - mHoverModifiedLine=-1; - } + if (cursor() == Qt::PointingHandCursor) + return; QSynedit::BufferCoord p; QPoint pos = mapFromGlobal(QCursor::pos()); @@ -1990,21 +2034,6 @@ void Editor::onTooltipTimer() } s = s.trimmed(); - if ((s == mCurrentWord) && (mCurrentTipType == reason)) { - if (mParser - && mParser->enabled() - && qApp->queryKeyboardModifiers() == Qt::ControlModifier) { - if (!hasFocus()) - activate(); - setCursor(Qt::PointingHandCursor); - } else { - updateMouseCursor(); - } - if (pointToLine(pos,line)) { - invalidateLine(line); - mHoverModifiedLine=line; - } - } // Remove hint cancelHint(); mCurrentWord = s; @@ -2085,25 +2114,10 @@ void Editor::onTooltipTimer() if (!hint.isEmpty()) { // QApplication* app = dynamic_cast(QApplication::instance()); // if (app->keyboardModifiers().testFlag(Qt::ControlModifier)) { - if (mParser - && mParser->enabled() - && qApp->queryKeyboardModifiers() == Qt::ControlModifier) { - if (!hasFocus()) - activate(); - setCursor(Qt::PointingHandCursor); - } else if (cursor() == Qt::PointingHandCursor) { - updateMouseCursor(); - } - if (pointToLine(pos,line)) { - invalidateLine(line); - mHoverModifiedLine=line; - } if (pMainWindow->functionTip()->isVisible()) { pMainWindow->functionTip()->hide(); } QToolTip::showText(mapToGlobal(pos),hint,this); - } else { - updateMouseCursor(); } } @@ -3422,11 +3436,6 @@ void Editor::showCompletion(const QString& preWord,bool autoComplete, CodeComple } } - // Position it at the top of the next line - QPoint p = rowColumnToPixels(displayXY()); - p+=QPoint(0,textHeight()+2); - mCompletionPopup->move(mapToGlobal(p)); - mCompletionPopup->setRecordUsage(pSettings->codeCompletion().recordUsage()); mCompletionPopup->setSortByScope(pSettings->codeCompletion().sortByScope()); mCompletionPopup->setShowKeywords(pSettings->codeCompletion().showKeywords()); @@ -3443,6 +3452,21 @@ void Editor::showCompletion(const QString& preWord,bool autoComplete, CodeComple mCompletionPopup->setIgnoreCase(pSettings->codeCompletion().ignoreCase()); mCompletionPopup->resize(pSettings->codeCompletion().width(), pSettings->codeCompletion().height()); + + // Position it at the top of the next line + QPoint popupPos = mapToGlobal(rowColumnToPixels(displayXY())); + QSize desktopSize = screen()->virtualSize(); + if (desktopSize.height() - popupPos.y() < mCompletionPopup->height() && popupPos.y() > mCompletionPopup->height()) + popupPos-=QPoint(0, mCompletionPopup->height()+2); + else + popupPos+=QPoint(0,textHeight()+2); + + if (desktopSize.width() - popupPos.x() < mCompletionPopup->width() ) { + popupPos.setX(std::max(0, desktopSize.width()-mCompletionPopup->width())-10); + } + + mCompletionPopup->move(popupPos); + // fCompletionBox.CodeInsList := dmMain.CodeInserts.ItemList; // fCompletionBox.SymbolUsage := dmMain.SymbolUsage; // fCompletionBox.ShowCount := devCodeCompletion.MaxCount; @@ -4024,17 +4048,10 @@ Editor::TipType Editor::getTipType(QPoint point, QSynedit::BufferCoord& pos) void Editor::cancelHint() { - if(mHoverModifiedLine!=-1) { - invalidateLine(mHoverModifiedLine); - mHoverModifiedLine=-1; - } - - // disable editor hint QToolTip::hideText(); mCurrentWord=""; mCurrentTipType=TipType::None; - updateMouseCursor(); } QString Editor::getFileHint(const QString &s, bool fromNext) @@ -4134,7 +4151,7 @@ QString Editor::getHintForFunction(const PStatement &statement, const QString& f void Editor::updateFunctionTip(bool showTip) { - if (pMainWindow->completionPopup()->isVisible()) { + if (mCompletionPopup->isVisible()) { pMainWindow->functionTip()->hide(); return; } @@ -4469,6 +4486,22 @@ void Editor::onScrollBarValueChanged() pMainWindow->functionTip()->hide(); } +void Editor::updateHoverLink(int line) +{ + setCursor(Qt::PointingHandCursor); + if (mHoverModifiedLine!=line) invalidateLine(mHoverModifiedLine); + mHoverModifiedLine=line; + invalidateLine(mHoverModifiedLine); +} + +void Editor::cancelHoverLink() +{ + if (mHoverModifiedLine != -1) { + invalidateLine(mHoverModifiedLine); + mHoverModifiedLine = -1; + } +} + PCppParser Editor::sharedParser(ParserLanguage language) { PCppParser parser; diff --git a/RedPandaIDE/editor.h b/RedPandaIDE/editor.h index e98a9534..0438ca06 100644 --- a/RedPandaIDE/editor.h +++ b/RedPandaIDE/editor.h @@ -298,6 +298,9 @@ private: void onExportedFormatToken(QSynedit::PSyntaxer syntaxer, int Line, int column, const QString& token, QSynedit::PTokenAttribute &attr); void onScrollBarValueChanged(); + void updateHoverLink(int line); + void cancelHoverLink(); + private: bool mInited; QDateTime mBackupTime; @@ -362,6 +365,8 @@ protected: void focusInEvent(QFocusEvent *event) override; void focusOutEvent(QFocusEvent *event) override; void keyPressEvent(QKeyEvent *event) override; + void keyReleaseEvent(QKeyEvent *event) override; + void mouseMoveEvent(QMouseEvent *event) override; // SynEdit interface protected: diff --git a/RedPandaIDE/parser/cppparser.cpp b/RedPandaIDE/parser/cppparser.cpp index dc84bc60..9093a217 100644 --- a/RedPandaIDE/parser/cppparser.cpp +++ b/RedPandaIDE/parser/cppparser.cpp @@ -4749,9 +4749,7 @@ PEvalStatement CppParser::doEvalCCast(const QString &fileName, // qDebug()<<"typeName"<baseStatement->type<baseStatement->command; PStatement typeStatement=doFindTypeDefinitionOf(fileName, typeName,parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope, result->baseStatement); } else { result = PEvalStatement(); } @@ -4760,9 +4758,7 @@ PEvalStatement CppParser::doEvalCCast(const QString &fileName, // qDebug()<<"typeName"<baseStatement->type<baseStatement->command; PStatement typeStatement=doFindTypeDefinitionOf(fileName, typeName,parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); } else { result = PEvalStatement(); } @@ -4784,9 +4780,7 @@ PEvalStatement CppParser::doEvalCCast(const QString &fileName, // qDebug()<<"typeName"<definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); } else { result = PEvalStatement(); } @@ -4931,9 +4925,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, if (!typeName.isEmpty()) typeStatement=doFindTypeDefinitionOf(fileName, typeName,parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString = typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); lastResult = result; } else { return PEvalStatement(); @@ -4950,9 +4942,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, if (!typeName.isEmpty()) typeStatement=doFindTypeDefinitionOf(fileName, typeName,parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString = typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); lastResult = result; } else { return PEvalStatement(); @@ -4984,9 +4974,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, typeStatement = doFindTypeDefinitionOf(fileName, typeName, parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); lastResult = result; } else { return PEvalStatement(); @@ -5001,9 +4989,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, typeStatement = doFindTypeDefinitionOf(fileName, typeName, parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); lastResult = result; } else { return PEvalStatement(); @@ -5037,9 +5023,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, // qDebug()<<"typeName"<baseStatement->type<baseStatement->command; PStatement typeStatement=doFindTypeDefinitionOf(fileName, typeName,parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); } else { result = PEvalStatement(); } @@ -5048,9 +5032,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, // qDebug()<<"typeName"<baseStatement->type<baseStatement->command; PStatement typeStatement=doFindTypeDefinitionOf(fileName, typeName,parentScope); if (typeStatement) { - result = doCreateEvalType(fileName,typeName,parentScope); - result->definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); } else { result = PEvalStatement(); } @@ -5071,9 +5053,7 @@ PEvalStatement CppParser::doEvalMemberAccess(const QString &fileName, // qDebug()<<"typeName"<definitionString=typeName; - result->kind = EvalStatementKind::Variable; + result = doCreateTypedEvalVar(fileName,typeName,parentScope,result->baseStatement); } else { return PEvalStatement(); } @@ -5512,6 +5492,15 @@ PEvalStatement CppParser::doCreateEvalType(const QString &primitiveType) const PStatement()); } +PEvalStatement CppParser::doCreateTypedEvalVar(const QString &fileName, const QString &typeName, const PStatement &parentScope, const PStatement &baseStatement) const +{ + PEvalStatement result = doCreateEvalType(fileName,typeName,parentScope); + result->definitionString=typeName; + result->kind = EvalStatementKind::Variable; + result->baseStatement = baseStatement; + return result; +} + PEvalStatement CppParser::doCreateEvalVariable( const QString &fileName, const PStatement& varStatement, diff --git a/RedPandaIDE/parser/cppparser.h b/RedPandaIDE/parser/cppparser.h index 5e3a93b0..5f93fa46 100644 --- a/RedPandaIDE/parser/cppparser.h +++ b/RedPandaIDE/parser/cppparser.h @@ -375,6 +375,8 @@ private: PEvalStatement doCreateEvalType(const QString& fileName,const PStatement& typeStatement) const; PEvalStatement doCreateEvalType(const QString& primitiveType) const; + PEvalStatement doCreateTypedEvalVar(const QString& fileName,const QString& typeName, const PStatement& parentScope, const PStatement &baseStatement) const; + PEvalStatement doCreateEvalVariable( const QString& fileName, const PStatement& varStatement, diff --git a/Red_Panda_CPP.pro b/Red_Panda_CPP.pro index c7e6d357..d0bbce1b 100644 --- a/Red_Panda_CPP.pro +++ b/Red_Panda_CPP.pro @@ -12,10 +12,6 @@ consolepauser.subdir = tools/consolepauser redpanda_qt_utils.subdir = libs/redpanda_qt_utils qsynedit.subdir = libs/qsynedit -APP_NAME = RedPandaCPP - -APP_VERSION = 2.25 - # Add the dependencies so that the RedPandaIDE project can add the depended programs # into the main app bundle RedPandaIDE.depends = astyle consolepauser qsynedit