forked from qt-creator/qt-creator
Editor: Animate automatic completed text.
This gives a clear hint that something has changed. And gets the attention of the author in the case he didn't expect some kind of automatic brace or quote completion. Change-Id: I33e383db9a1e797ecb285a407e46671f41be7051 Reviewed-by: Alessandro Portale <alessandro.portale@theqtcompany.com>
This commit is contained in:
@@ -28,6 +28,7 @@
|
||||
<style name="Operator" foreground="#aaaaaa"/>
|
||||
<style name="Parentheses" foreground="#ff5555" background="#333333"/>
|
||||
<style name="ParenthesesMismatch" background="#800080"/>
|
||||
<style name="AutoComplete" foreground="#a0a0ff" background="#333333"/>
|
||||
<style name="Preprocessor" foreground="#5555ff"/>
|
||||
<style name="SearchResult" background="#555500"/>
|
||||
<style name="SearchScope" background="#222200"/>
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
<style name="Operator"/>
|
||||
<style name="Parentheses" background="#e3e3e3" bold="true"/>
|
||||
<style name="ParenthesesMismatch" background="#808080"/>
|
||||
<style name="AutoComplete" foreground="#303030" background="#d0d0d0"/>
|
||||
<style name="Preprocessor" foreground="#5b5b5b" bold="true"/>
|
||||
<style name="RemovedLine" foreground="#a0a0a4"/>
|
||||
<style name="Static" italic="true"/>
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
<style name="Operator" foreground="#cfbfad"/>
|
||||
<style name="Parentheses" foreground="#ffff00" background="#4e4e8f"/>
|
||||
<style name="ParenthesesMismatch" background="#404040"/>
|
||||
<style name="AutoComplete" foreground="#ffff00" background="#4e4e8f"/>
|
||||
<style name="Preprocessor" foreground="#409090"/>
|
||||
<style name="RemovedLine" foreground="#ff0000"/>
|
||||
<style name="SearchResult" foreground="#000000" background="#ffef0b"/>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
<style name="Operator" foreground="#000000"/>
|
||||
<style name="Parentheses" foreground="#ff0000" background="#c3e1ff"/>
|
||||
<style name="ParenthesesMismatch" background="#ff00ff"/>
|
||||
<style name="AutoComplete" foreground="#ff0000" background="#c3e1ff"/>
|
||||
<style name="Preprocessor" foreground="#000080" bold="true"/>
|
||||
<style name="RemovedLine" foreground="#ff0000"/>
|
||||
<style name="String" foreground="#008000" bold="true"/>
|
||||
|
||||
@@ -38,6 +38,7 @@ static const char surroundingAutoQuotesKey[] = "SurroundingAutoQuotes";
|
||||
static const char partiallyCompleteKey[] = "PartiallyComplete";
|
||||
static const char spaceAfterFunctionNameKey[] = "SpaceAfterFunctionName";
|
||||
static const char autoSplitStringsKey[] = "AutoSplitStrings";
|
||||
static const char animateAutoCompleteKey[] = "AnimateAutoComplete";
|
||||
|
||||
using namespace TextEditor;
|
||||
|
||||
@@ -54,6 +55,7 @@ void CompletionSettings::toSettings(QSettings *s) const
|
||||
s->setValue(partiallyCompleteKey, m_partiallyComplete);
|
||||
s->setValue(spaceAfterFunctionNameKey, m_spaceAfterFunctionName);
|
||||
s->setValue(autoSplitStringsKey, m_autoSplitStrings);
|
||||
s->setValue(animateAutoCompleteKey, m_animateAutoComplete);
|
||||
s->endGroup();
|
||||
}
|
||||
|
||||
@@ -82,6 +84,8 @@ void CompletionSettings::fromSettings(QSettings *s)
|
||||
s->value(spaceAfterFunctionNameKey, m_spaceAfterFunctionName).toBool();
|
||||
m_autoSplitStrings =
|
||||
s->value(autoSplitStringsKey, m_autoSplitStrings).toBool();
|
||||
m_animateAutoComplete =
|
||||
s->value(animateAutoCompleteKey, m_animateAutoComplete).toBool();
|
||||
s->endGroup();
|
||||
}
|
||||
|
||||
@@ -97,5 +101,6 @@ bool CompletionSettings::equals(const CompletionSettings &cs) const
|
||||
&& m_partiallyComplete == cs.m_partiallyComplete
|
||||
&& m_spaceAfterFunctionName == cs.m_spaceAfterFunctionName
|
||||
&& m_autoSplitStrings == cs.m_autoSplitStrings
|
||||
&& m_animateAutoComplete == cs.m_animateAutoComplete
|
||||
;
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ public:
|
||||
bool m_partiallyComplete = true;
|
||||
bool m_spaceAfterFunctionName = false;
|
||||
bool m_autoSplitStrings = true;
|
||||
bool m_animateAutoComplete = true;
|
||||
};
|
||||
|
||||
inline bool operator==(const CompletionSettings &t1, const CompletionSettings &t2) { return t1.equals(t2); }
|
||||
|
||||
@@ -102,6 +102,7 @@ QWidget *CompletionSettingsPage::widget()
|
||||
m_page->partiallyComplete->setChecked(m_completionSettings.m_partiallyComplete);
|
||||
m_page->spaceAfterFunctionName->setChecked(m_completionSettings.m_spaceAfterFunctionName);
|
||||
m_page->autoSplitStrings->setChecked(m_completionSettings.m_autoSplitStrings);
|
||||
m_page->animateAutoComplete->setChecked(m_completionSettings.m_animateAutoComplete);
|
||||
|
||||
m_page->enableDoxygenCheckBox->setChecked(m_commentsSettings.m_enableDoxygen);
|
||||
m_page->generateBriefCheckBox->setChecked(m_commentsSettings.m_generateBrief);
|
||||
@@ -175,6 +176,7 @@ void CompletionSettingsPage::settingsFromUi(CompletionSettings &completion, Comm
|
||||
completion.m_partiallyComplete = m_page->partiallyComplete->isChecked();
|
||||
completion.m_spaceAfterFunctionName = m_page->spaceAfterFunctionName->isChecked();
|
||||
completion.m_autoSplitStrings = m_page->autoSplitStrings->isChecked();
|
||||
completion.m_animateAutoComplete = m_page->animateAutoComplete->isChecked();
|
||||
|
||||
comment.m_enableDoxygen = m_page->enableDoxygenCheckBox->isChecked();
|
||||
comment.m_generateBrief = m_page->generateBriefCheckBox->isChecked();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TextEditor::Internal::CompletionSettingsPage</class>
|
||||
<widget class="QWidget" name="CppTools::Internal::CompletionSettingsPage">
|
||||
<widget class="QWidget" name="TextEditor::Internal::CompletionSettingsPage">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
@@ -214,6 +214,19 @@ In addition, Shift+Enter inserts an escape character at the cursor position and
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="animateAutoComplete">
|
||||
<property name="toolTip">
|
||||
<string>Show a visual hint when for example a brace or a quote is automatically inserted by the editor.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Animate automatically inserted text</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -302,6 +315,7 @@ In addition, Shift+Enter inserts an escape character at the cursor position and
|
||||
<tabstop>surroundBrackets</tabstop>
|
||||
<tabstop>surroundQuotes</tabstop>
|
||||
<tabstop>spaceAfterFunctionName</tabstop>
|
||||
<tabstop>animateAutoComplete</tabstop>
|
||||
<tabstop>enableDoxygenCheckBox</tabstop>
|
||||
<tabstop>generateBriefCheckBox</tabstop>
|
||||
<tabstop>leadingAsterisksCheckBox</tabstop>
|
||||
|
||||
@@ -263,6 +263,8 @@ QColor FormatDescription::foreground() const
|
||||
return m_format.foreground();
|
||||
} else if (m_id == C_PARENTHESES) {
|
||||
return QColor(Qt::red);
|
||||
} else if (m_id == C_AUTOCOMPLETE) {
|
||||
return QColor(Qt::darkBlue);
|
||||
}
|
||||
return m_format.foreground();
|
||||
}
|
||||
@@ -279,6 +281,8 @@ QColor FormatDescription::background() const
|
||||
return QColor(0xb4, 0xee, 0xb4);
|
||||
} else if (m_id == C_PARENTHESES_MISMATCH) {
|
||||
return QColor(Qt::magenta);
|
||||
} else if (m_id == C_AUTOCOMPLETE) {
|
||||
return QColor(192, 192, 255);
|
||||
} else if (m_id == C_CURRENT_LINE || m_id == C_SEARCH_SCOPE) {
|
||||
const QPalette palette = QApplication::palette();
|
||||
const QColor &fg = palette.color(QPalette::Highlight);
|
||||
|
||||
@@ -329,6 +329,9 @@ public:
|
||||
// parentheses matcher
|
||||
void _q_matchParentheses();
|
||||
void _q_highlightBlocks();
|
||||
void _q_autocompleterHighlight(const QTextCursor &cursor = QTextCursor());
|
||||
void updateAnimator(QPointer<TextEditorAnimator> animator, QPainter &painter);
|
||||
void cancelCurrentAnimations();
|
||||
void slotSelectionChanged();
|
||||
void _q_animateUpdate(int position, QPointF lastPos, QRectF rect);
|
||||
void updateCodeFoldingVisible();
|
||||
@@ -450,7 +453,9 @@ public:
|
||||
bool m_assistRelevantContentAdded;
|
||||
QList<BaseHoverHandler *> m_hoverHandlers; // Not owned
|
||||
|
||||
QPointer<TextEditorAnimator> m_animator;
|
||||
QPointer<TextEditorAnimator> m_bracketsAnimator;
|
||||
QPointer<TextEditorAnimator> m_autocompleteAnimator;
|
||||
bool m_animateAutoComplete = true;
|
||||
int m_cursorBlockNumber;
|
||||
int m_blockCount;
|
||||
|
||||
@@ -738,7 +743,8 @@ void TextEditorWidgetPrivate::ctor(const QSharedPointer<TextDocument> &doc)
|
||||
QObject::connect(&m_scrollBarUpdateTimer, &QTimer::timeout,
|
||||
this, &TextEditorWidgetPrivate::highlightSearchResultsInScrollBar);
|
||||
|
||||
m_animator = 0;
|
||||
m_bracketsAnimator = 0;
|
||||
m_autocompleteAnimator = 0;
|
||||
|
||||
slotUpdateExtraAreaWidth();
|
||||
updateHighlights();
|
||||
@@ -1104,8 +1110,8 @@ TextEditorWidget *TextEditorWidget::currentTextEditorWidget()
|
||||
|
||||
void TextEditorWidgetPrivate::editorContentsChange(int position, int charsRemoved, int charsAdded)
|
||||
{
|
||||
if (m_animator)
|
||||
m_animator->finish();
|
||||
if (m_bracketsAnimator)
|
||||
m_bracketsAnimator->finish();
|
||||
|
||||
m_contentsChanged = true;
|
||||
QTextDocument *doc = q->document();
|
||||
@@ -2152,6 +2158,13 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
||||
d->m_document->autoIndent(ensureVisible);
|
||||
else if (!previousIndentationString.isEmpty())
|
||||
ensureVisible.insertText(previousIndentationString);
|
||||
if (d->m_animateAutoComplete) {
|
||||
QTextCursor tc = ensureVisible;
|
||||
tc.movePosition(QTextCursor::EndOfBlock);
|
||||
tc.movePosition(QTextCursor::StartOfBlock, QTextCursor::KeepAnchor);
|
||||
tc.movePosition(QTextCursor::NextWord, QTextCursor::KeepAnchor);
|
||||
d->_q_autocompleterHighlight(tc);
|
||||
}
|
||||
}
|
||||
setTextCursor(ensureVisible);
|
||||
}
|
||||
@@ -2424,6 +2437,7 @@ void TextEditorWidget::keyPressEvent(QKeyEvent *e)
|
||||
cursor.insertText(autoText);
|
||||
//Select the inserted text, to be able to re-indent the inserted text
|
||||
cursor.setPosition(pos, QTextCursor::KeepAnchor);
|
||||
d->_q_autocompleterHighlight(cursor);
|
||||
}
|
||||
if (!electricChar.isNull() && d->m_autoCompleter->contextAllowsElectricCharacters(cursor))
|
||||
d->m_document->autoIndent(cursor, electricChar);
|
||||
@@ -4224,11 +4238,8 @@ void TextEditorWidget::paintEvent(QPaintEvent *e)
|
||||
bottom = top + blockBoundingRect(block).height();
|
||||
}
|
||||
|
||||
if (d->m_animator && d->m_animator->isRunning()) {
|
||||
QTextCursor cursor = textCursor();
|
||||
cursor.setPosition(d->m_animator->position());
|
||||
d->m_animator->draw(&painter, cursorRect(cursor).topLeft());
|
||||
}
|
||||
d->updateAnimator(d->m_bracketsAnimator, painter);
|
||||
d->updateAnimator(d->m_autocompleteAnimator, painter);
|
||||
|
||||
// draw the overlays, but only if we do not have a find scope, otherwise the
|
||||
// view becomes too noisy.
|
||||
@@ -4735,7 +4746,7 @@ void TextEditorWidgetPrivate::updateHighlights()
|
||||
if (m_parenthesesMatchingEnabled && q->hasFocus()) {
|
||||
// Delay update when no matching is displayed yet, to avoid flicker
|
||||
if (q->extraSelections(TextEditorWidget::ParenthesesMatchingSelection).isEmpty()
|
||||
&& m_animator == 0) {
|
||||
&& m_bracketsAnimator == 0) {
|
||||
m_parenthesesMatchingTimer.start(50);
|
||||
} else {
|
||||
// when we uncheck "highlight matching parentheses"
|
||||
@@ -5995,15 +6006,15 @@ void TextEditorWidgetPrivate::_q_matchParentheses()
|
||||
}
|
||||
|
||||
if (animatePosition >= 0) {
|
||||
if (m_animator)
|
||||
m_animator->finish(); // one animation is enough
|
||||
m_animator = new TextEditorAnimator(this);
|
||||
m_animator->setPosition(animatePosition);
|
||||
cancelCurrentAnimations();// one animation is enough
|
||||
m_bracketsAnimator = new TextEditorAnimator(this);
|
||||
m_bracketsAnimator->setPosition(animatePosition);
|
||||
QPalette pal;
|
||||
pal.setBrush(QPalette::Text, matchFormat.foreground());
|
||||
pal.setBrush(QPalette::Base, matchFormat.background());
|
||||
m_animator->setData(q->font(), pal, q->document()->characterAt(m_animator->position()));
|
||||
connect(m_animator.data(), &TextEditorAnimator::updateRequest,
|
||||
m_bracketsAnimator->setData(
|
||||
q->font(), pal, q->document()->characterAt(m_bracketsAnimator->position()));
|
||||
connect(m_bracketsAnimator.data(), &TextEditorAnimator::updateRequest,
|
||||
this, &TextEditorWidgetPrivate::_q_animateUpdate);
|
||||
}
|
||||
if (m_displaySettings.m_highlightMatchingParentheses)
|
||||
@@ -6071,6 +6082,43 @@ void TextEditorWidgetPrivate::_q_highlightBlocks()
|
||||
}
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::_q_autocompleterHighlight(const QTextCursor &cursor)
|
||||
{
|
||||
if (!m_animateAutoComplete || q->isReadOnly() || !cursor.hasSelection())
|
||||
return;
|
||||
|
||||
const QTextCharFormat &matchFormat
|
||||
= q->textDocument()->fontSettings().toTextCharFormat(C_AUTOCOMPLETE);
|
||||
|
||||
cancelCurrentAnimations();// one animation is enough
|
||||
m_autocompleteAnimator = new TextEditorAnimator(this);
|
||||
m_autocompleteAnimator->setPosition(cursor.selectionStart());
|
||||
QPalette pal;
|
||||
pal.setBrush(QPalette::Text, matchFormat.foreground());
|
||||
pal.setBrush(QPalette::Base, matchFormat.background());
|
||||
m_autocompleteAnimator->setData(q->font(), pal, cursor.selectedText());
|
||||
connect(m_autocompleteAnimator.data(), &TextEditorAnimator::updateRequest,
|
||||
this, &TextEditorWidgetPrivate::_q_animateUpdate);
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::updateAnimator(QPointer<TextEditorAnimator> animator,
|
||||
QPainter &painter)
|
||||
{
|
||||
if (animator && animator->isRunning()) {
|
||||
QTextCursor cursor = q->textCursor();
|
||||
cursor.setPosition(animator->position());
|
||||
animator->draw(&painter, q->cursorRect(cursor).topLeft());
|
||||
}
|
||||
}
|
||||
|
||||
void TextEditorWidgetPrivate::cancelCurrentAnimations()
|
||||
{
|
||||
if (m_autocompleteAnimator)
|
||||
m_autocompleteAnimator->finish();
|
||||
if (m_bracketsAnimator)
|
||||
m_bracketsAnimator->finish();
|
||||
}
|
||||
|
||||
void TextEditorWidget::changeEvent(QEvent *e)
|
||||
{
|
||||
QPlainTextEdit::changeEvent(e);
|
||||
@@ -6549,6 +6597,7 @@ void TextEditorWidget::setCompletionSettings(const CompletionSettings &completio
|
||||
d->m_autoCompleter->setSurroundWithBracketsEnabled(completionSettings.m_surroundingAutoBrackets);
|
||||
d->m_autoCompleter->setAutoInsertQuotesEnabled(completionSettings.m_autoInsertQuotes);
|
||||
d->m_autoCompleter->setSurroundWithQuotesEnabled(completionSettings.m_surroundingAutoQuotes);
|
||||
d->m_animateAutoComplete = completionSettings.m_animateAutoComplete;
|
||||
}
|
||||
|
||||
void TextEditorWidget::setExtraEncodingSettings(const ExtraEncodingSettings &extraEncodingSettings)
|
||||
|
||||
@@ -42,6 +42,7 @@ const char *nameForStyle(TextStyle style)
|
||||
case C_SEARCH_SCOPE: return "SearchScope";
|
||||
case C_PARENTHESES: return "Parentheses";
|
||||
case C_PARENTHESES_MISMATCH:return "ParenthesesMismatch";
|
||||
case C_AUTOCOMPLETE: return "AutoComplete";
|
||||
case C_CURRENT_LINE: return "CurrentLine";
|
||||
case C_CURRENT_LINE_NUMBER: return "CurrentLineNumber";
|
||||
case C_OCCURRENCES: return "Occurrences";
|
||||
|
||||
@@ -40,6 +40,7 @@ enum TextStyle : quint8 {
|
||||
C_SEARCH_SCOPE,
|
||||
C_PARENTHESES,
|
||||
C_PARENTHESES_MISMATCH,
|
||||
C_AUTOCOMPLETE,
|
||||
C_CURRENT_LINE,
|
||||
C_CURRENT_LINE_NUMBER,
|
||||
C_OCCURRENCES,
|
||||
|
||||
@@ -118,6 +118,9 @@ TextEditorSettings::TextEditorSettings(QObject *parent)
|
||||
formatDescr.emplace_back(C_PARENTHESES_MISMATCH, tr("Mismatched Parentheses"),
|
||||
tr("Displayed when mismatched parentheses, "
|
||||
"square brackets, or curly brackets are found."));
|
||||
formatDescr.emplace_back(C_AUTOCOMPLETE, tr("Auto Complete"),
|
||||
tr("Displayed when a character is automatically inserted "
|
||||
"like brackets or quotes."));
|
||||
formatDescr.emplace_back(C_CURRENT_LINE, tr("Current Line"),
|
||||
tr("Line where the cursor is placed in."),
|
||||
FormatDescription::ShowBackgroundControl);
|
||||
|
||||
Reference in New Issue
Block a user