- enhancement: Delay for tooltips.

- enhancement: "Tool tips delay" option in Options/editor/Tooltips
This commit is contained in:
Roy Qu 2023-02-17 09:03:35 +08:00
parent a8d9550632
commit 8254de68c8
10 changed files with 813 additions and 549 deletions

View File

@ -31,6 +31,8 @@ Red Panda C++ Version 2.12
- enhancement: Parser not correctly released if save a c file to non-c file.
- enhancement: Improve auto indent for embedding no-brace statements like for-for-if.
- enhancement: Toggle comment for asm/makefile/lua files.
- enhancement: Delay for tooltips.
- enhancement: "Tool tips delay" option in Options/editor/Tooltips
Red Panda C++ Version 2.11

View File

@ -195,6 +195,8 @@ Editor::Editor(QWidget *parent, const QString& filename,
mAutoBackupTimer.setInterval(1);
connect(&mAutoBackupTimer, &QTimer::timeout,
this, &Editor::onAutoBackupTimer);
connect(&mTooltipTimer, &QTimer::timeout,
this, &Editor::onTooltipTimer);
}
connect(horizontalScrollBar(), &QScrollBar::valueChanged,
@ -1233,169 +1235,21 @@ bool Editor::event(QEvent *event)
&& !pMainWindow->completionPopup()->isVisible()
&& !pMainWindow->functionTip()->isVisible()
&& !pMainWindow->headerCompletionPopup()->isVisible()) {
if(mHoverModifiedLine!=-1) {
invalidateLine(mHoverModifiedLine);
mHoverModifiedLine=-1;
}
QHoverEvent *helpEvent = static_cast<QHoverEvent *>(event);
QSynedit::BufferCoord p;
TipType reason = getTipType(helpEvent->pos(),p);
PSyntaxIssue pError;
int line ;
if (reason == TipType::Error) {
pError = getSyntaxIssueAtPosition(p);
} else if (pointToLine(helpEvent->pos(),line)) {
//issue tips is prefered
PSyntaxIssueList issues = getSyntaxIssuesAtLine(line);
if (issues && !issues->isEmpty()) {
reason = TipType::Error;
pError = issues->front();
}
}
// Get subject
bool isIncludeLine = false;
bool isIncludeNextLine = false;
QSynedit::BufferCoord pBeginPos,pEndPos;
QString s;
QStringList expression;
switch (reason) {
case TipType::Preprocessor:
// When hovering above a preprocessor line, determine if we want to show an include or a identifier hint
if (mParser) {
s = document()->getLine(p.line - 1);
isIncludeNextLine = mParser->isIncludeNextLine(s);
if (!isIncludeNextLine)
isIncludeLine = mParser->isIncludeLine(s);
if (!isIncludeNextLine &&!isIncludeLine)
s = wordAtRowCol(p);
}
break;
case TipType::Identifier:
if (pMainWindow->debugger()->executing() && !pMainWindow->debugger()->inferiorRunning())
s = getWordAtPosition(this,p, pBeginPos,pEndPos, WordPurpose::wpEvaluation); // debugging
else if (!mCompletionPopup->isVisible()
&& !mHeaderCompletionPopup->isVisible()) {
expression = getExpressionAtPosition(p);
s = expression.join(""); // information during coding
}
break;
case TipType::Selection:
s = selText(); // when a selection is available, always only use that
break;
case TipType::Error:
s = pError->token;
break;
case TipType::None:
cancelHint();
mCurrentWord = "";
mCurrentTipType = TipType::None;
event->ignore();
return true;
}
s = s.trimmed();
if ((s == mCurrentWord) && (mCurrentTipType == reason)) {
if (mParser
&& mParser->enabled()
&& qApp->queryKeyboardModifiers() == Qt::ControlModifier) {
if (!hasFocus())
activate();
setCursor(Qt::PointingHandCursor);
mTooltipTimer.stop();
if (pSettings->editor().tipsDelay()>0) {
mTooltipTimer.setSingleShot(true);
mTooltipTimer.start(pSettings->editor().tipsDelay());
} else {
updateMouseCursor();
}
if (pointToLine(helpEvent->pos(),line)) {
invalidateLine(line);
mHoverModifiedLine=line;
onTooltipTimer();
}
event->ignore();
return true; // do NOT remove hint when subject stays the same
}
// Remove hint
cancelHint();
mCurrentWord = s;
mCurrentTipType = reason;
// Determine what to do with subject
QString hint = "";
switch (reason) {
case TipType::Preprocessor:
if (isIncludeNextLine || isIncludeLine) {
if (pSettings->editor().enableHeaderToolTips())
hint = getFileHint(s, isIncludeNextLine);
} else if (//devEditor.ParserHints and
!mCompletionPopup->isVisible()
&& !mHeaderCompletionPopup->isVisible()) {
if (pSettings->editor().enableIdentifierToolTips())
hint = getParserHint(QStringList(),s,p.line);
}
break;
case TipType::Identifier:
case TipType::Selection:
if (!mCompletionPopup->isVisible()
&& !mHeaderCompletionPopup->isVisible()) {
if (pMainWindow->debugger()->executing()
&& (pSettings->editor().enableDebugTooltips())) {
showDebugHint(s,p.line);
} else if (pSettings->editor().enableIdentifierToolTips()) { //if devEditor.ParserHints {
hint = getParserHint(expression, s, p.line);
}
}
break;
case TipType::Error:
if (pSettings->editor().enableIssueToolTips())
hint = getErrorHint(pError);
break;
default:
break;
}
// qDebug()<<"hint:"<<hint;
if (!hint.isEmpty()) {
// QApplication* app = dynamic_cast<QApplication *>(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(helpEvent->pos(),line)) {
invalidateLine(line);
mHoverModifiedLine=line;
}
if (pMainWindow->functionTip()->isVisible()) {
pMainWindow->functionTip()->hide();
}
QToolTip::showText(mapToGlobal(helpEvent->pos()),hint,this);
event->ignore();
} else {
updateMouseCursor();
event->ignore();
}
return true;
} else if (event->type() == QEvent::HoverLeave) {
cancelHint();
return true;
} else if (event->type() == QEvent::KeyPress || event->type() == QEvent::KeyRelease ) {
if (!mCurrentWord.isEmpty()) {
QKeyEvent* keyEvent = dynamic_cast<QKeyEvent*>(event);
if (keyEvent->key() == Qt::Key_Control) {
QApplication* app = dynamic_cast<QApplication *>(QApplication::instance());
//postEvent takes the owner ship
QHoverEvent* hoverEvent=new QHoverEvent(QEvent::HoverMove,
mapFromGlobal(QCursor::pos()),
mapFromGlobal(QCursor::pos()),
Qt::ControlModifier
);
app->postEvent(this,hoverEvent);
}
onTooltipTimer();
}
}
return QSynEdit::event(event);
@ -1408,7 +1262,7 @@ void Editor::mouseReleaseEvent(QMouseEvent *event)
}
// if ctrl+clicked
if ((cursor() == Qt::PointingHandCursor) && (event->modifiers() == Qt::ControlModifier)
if ((event->modifiers() == Qt::ControlModifier)
&& (event->button() == Qt::LeftButton)) {
QSynedit::BufferCoord p;
@ -1886,8 +1740,10 @@ void Editor::onStatusChanged(QSynedit::StatusChanges changes)
if (pSettings->editor().showFunctionTips()) {
updateFunctionTip(false);
mFunctionTipTimer.stop();
if (pSettings->editor().tipsDelay()>0)
mFunctionTipTimer.start(500);
// updateFunctionTip();
else
onFunctionTipsTimer();
}
}
@ -1970,6 +1826,151 @@ void Editor::onAutoBackupTimer()
saveAutoBackup();
}
void Editor::onTooltipTimer()
{
if(mHoverModifiedLine!=-1) {
invalidateLine(mHoverModifiedLine);
mHoverModifiedLine=-1;
}
QSynedit::BufferCoord p;
QPoint pos = mapFromGlobal(QCursor::pos());
TipType reason = getTipType(pos,p);
PSyntaxIssue pError;
int line ;
if (reason == TipType::Error) {
pError = getSyntaxIssueAtPosition(p);
} else if (pointToLine(pos,line)) {
//issue tips is prefered
PSyntaxIssueList issues = getSyntaxIssuesAtLine(line);
if (issues && !issues->isEmpty()) {
reason = TipType::Error;
pError = issues->front();
}
}
// Get subject
bool isIncludeLine = false;
bool isIncludeNextLine = false;
QSynedit::BufferCoord pBeginPos,pEndPos;
QString s;
QStringList expression;
switch (reason) {
case TipType::Preprocessor:
// When hovering above a preprocessor line, determine if we want to show an include or a identifier hint
if (mParser) {
s = document()->getLine(p.line - 1);
isIncludeNextLine = mParser->isIncludeNextLine(s);
if (!isIncludeNextLine)
isIncludeLine = mParser->isIncludeLine(s);
if (!isIncludeNextLine &&!isIncludeLine)
s = wordAtRowCol(p);
}
break;
case TipType::Identifier:
if (pMainWindow->debugger()->executing() && !pMainWindow->debugger()->inferiorRunning())
s = getWordAtPosition(this,p, pBeginPos,pEndPos, WordPurpose::wpEvaluation); // debugging
else if (!mCompletionPopup->isVisible()
&& !mHeaderCompletionPopup->isVisible()) {
expression = getExpressionAtPosition(p);
s = expression.join(""); // information during coding
}
break;
case TipType::Selection:
s = selText(); // when a selection is available, always only use that
break;
case TipType::Error:
s = pError->token;
break;
case TipType::None:
cancelHint();
mCurrentWord = "";
mCurrentTipType = TipType::None;
return;
}
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;
mCurrentTipType = reason;
// Determine what to do with subject
QString hint = "";
switch (reason) {
case TipType::Preprocessor:
if (isIncludeNextLine || isIncludeLine) {
if (pSettings->editor().enableHeaderToolTips())
hint = getFileHint(s, isIncludeNextLine);
} else if (//devEditor.ParserHints and
!mCompletionPopup->isVisible()
&& !mHeaderCompletionPopup->isVisible()) {
if (pSettings->editor().enableIdentifierToolTips())
hint = getParserHint(QStringList(),s,p.line);
}
break;
case TipType::Identifier:
case TipType::Selection:
if (!mCompletionPopup->isVisible()
&& !mHeaderCompletionPopup->isVisible()) {
if (pMainWindow->debugger()->executing()
&& (pSettings->editor().enableDebugTooltips())) {
showDebugHint(s,p.line);
} else if (pSettings->editor().enableIdentifierToolTips()) { //if devEditor.ParserHints {
hint = getParserHint(expression, s, p.line);
}
}
break;
case TipType::Error:
if (pSettings->editor().enableIssueToolTips())
hint = getErrorHint(pError);
break;
default:
break;
}
// qDebug()<<"hint:"<<hint;
if (!hint.isEmpty()) {
// QApplication* app = dynamic_cast<QApplication *>(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();
}
}
void Editor::resolveAutoDetectEncodingOption()
{
if (mEncodingOption==ENCODING_AUTO_DETECT) {
@ -3829,8 +3830,8 @@ void Editor::cancelHint()
// disable editor hint
QToolTip::hideText();
//mCurrentWord = "";
//mCurrentTipType = TipType::None;
mCurrentWord="";
mCurrentTipType=TipType::None;
updateMouseCursor();
}

View File

@ -236,6 +236,7 @@ private slots:
void onLinesInserted(int first,int count);
void onFunctionTipsTimer();
void onAutoBackupTimer();
void onTooltipTimer();
private:
void resolveAutoDetectEncodingOption();
@ -344,6 +345,7 @@ private:
std::shared_ptr<QHash<StatementKind, std::shared_ptr<ColorSchemeItem> > > mStatementColors;
QTimer mFunctionTipTimer;
QTimer mAutoBackupTimer;
QTimer mTooltipTimer;
int mHoverModifiedLine;
static QHash<ParserLanguage,std::weak_ptr<CppParser>> mSharedParsers;

View File

@ -777,6 +777,16 @@ void Settings::Editor::setEnableEditTempBackup(bool newEnableEditTempBackup)
mEnableEditTempBackup = newEnableEditTempBackup;
}
int Settings::Editor::tipsDelay() const
{
return mTipsDelay;
}
void Settings::Editor::setTipsDelay(int newTipsDelay)
{
mTipsDelay = newTipsDelay;
}
bool Settings::Editor::showTrailingSpaces() const
{
return mShowTrailingSpaces;
@ -1408,6 +1418,7 @@ void Settings::Editor::doSave()
saveValue("enable_header_tooltips",mEnableHeaderToolTips);
saveValue("enable_issue_tooltips",mEnableIssueToolTips);
saveValue("show_function_tips",mShowFunctionTips);
saveValue("tips_delay",mTipsDelay);
}
void Settings::Editor::doLoad()
@ -1563,6 +1574,7 @@ void Settings::Editor::doLoad()
mEnableHeaderToolTips = boolValue("enable_header_tooltips", true);
mEnableIssueToolTips = boolValue("enable_issue_tooltips", true);
mShowFunctionTips = boolValue("show_function_tips",true);
mTipsDelay = intValue("tips_delay",500);
}
QSynedit::EditCaretType Settings::Editor::caretForOverwrite() const

View File

@ -402,6 +402,9 @@ public:
bool enableEditTempBackup() const;
void setEnableEditTempBackup(bool newEnableEditTempBackup);
int tipsDelay() const;
void setTipsDelay(int newTipsDelay);
private:
//General
// indents
@ -527,6 +530,7 @@ public:
//hints tooltip
int mTipsDelay;
bool mEnableTooltips;
bool mEnableDebugTooltips;
bool mEnableIdentifierToolTips;

View File

@ -38,7 +38,7 @@ void EditorTooltipsWidget::doLoad()
ui->chkIdentifierTooltips->setChecked(pSettings->editor().enableIdentifierToolTips());
ui->chkHeaderTooltips->setChecked(pSettings->editor().enableHeaderToolTips());
ui->chkDebugTooltips->setChecked(pSettings->editor().enableDebugTooltips());
ui->spinTipsDelay->setValue(pSettings->editor().tipsDelay());
}
void EditorTooltipsWidget::doSave()
@ -49,5 +49,6 @@ void EditorTooltipsWidget::doSave()
pSettings->editor().setEnableIdentifierToolTips(ui->chkIdentifierTooltips->isChecked());
pSettings->editor().setEnableHeaderToolTips(ui->chkHeaderTooltips->isChecked());
pSettings->editor().setEnableDebugTooltips(ui->chkDebugTooltips->isChecked());
pSettings->editor().setTipsDelay(ui->spinTipsDelay->value());
pSettings->editor().save();
}

View File

@ -61,6 +61,57 @@
</layout>
</widget>
</item>
<item>
<widget class="QWidget" name="widget" native="true">
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Tool tips delay</string>
</property>
</widget>
</item>
<item>
<widget class="QSpinBox" name="spinTipsDelay">
<property name="suffix">
<string>ms</string>
</property>
<property name="maximum">
<number>5000</number>
</property>
<property name="singleStep">
<number>100</number>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">

View File

@ -1687,6 +1687,14 @@
<source>Show expression value tooltips when debugging</source>
<translation>Mostrar dicas com valor de expressão ao depurar</translation>
</message>
<message>
<source>Tool tips delay</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ms</source>
<translation type="unfinished">ms</translation>
</message>
</context>
<context>
<name>EnvironmentAppearenceWidget</name>
@ -6531,6 +6539,10 @@
<source>ASM files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Lua files</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RegisterModel</name>
@ -7472,6 +7484,53 @@
<translation>Valor</translation>
</message>
</context>
<context>
<name>XMakeCompiler</name>
<message>
<source>Building xmake.lua file...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>- Filename: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open &apos;%1&apos; for write!</source>
<translation type="unfinished">Impossível abrir &apos;%1&apos; para gravar!</translation>
</message>
<message>
<source>Compiling project changes...</source>
<translation type="unfinished">Compilando alterações em projeto ...</translation>
</message>
<message>
<source>- Project Filename: %1</source>
<translation type="unfinished">- Nome de arquivo de projeto: %1</translation>
</message>
<message>
<source>- Compiler Set Name: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Make program &apos;%1&apos; doesn&apos;t exists!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Please check the &quot;program&quot; page of compiler settings.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Processing makefile:</source>
<translation type="unfinished">Processando makefile:</translation>
</message>
<message>
<source>- makefile processer: %1</source>
<translation type="unfinished">- Processador do makefile: %1</translation>
</message>
<message>
<source>- Command: %1 %2</source>
<translation type="unfinished">- Comando: %1 %2</translation>
</message>
</context>
<context>
<name>editorcustomctypekeywords</name>
<message>

File diff suppressed because it is too large Load Diff

View File

@ -1564,6 +1564,14 @@
<source>Show expression value tooltips when debugging</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Tool tips delay</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>ms</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>EnvironmentAppearenceWidget</name>
@ -6152,6 +6160,10 @@
<source>ASM files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Lua files</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>RegisterModel</name>
@ -6955,6 +6967,53 @@
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>XMakeCompiler</name>
<message>
<source>Building xmake.lua file...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>- Filename: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Can&apos;t open &apos;%1&apos; for write!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Compiling project changes...</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>- Project Filename: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>- Compiler Set Name: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Make program &apos;%1&apos; doesn&apos;t exists!</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Please check the &quot;program&quot; page of compiler settings.</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Processing makefile:</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>- makefile processer: %1</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>- Command: %1 %2</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>editorcustomctypekeywords</name>
<message>