ui: draw scope annotations in CodeView using one big rectangle

And refactored QtCodeFile classes.
This commit is contained in:
Eberhard Graether
2015-05-16 12:57:47 +02:00
parent 8e9b7ec7bc
commit e4d71f8a01
9 changed files with 181 additions and 119 deletions
+1
View File
@@ -27,6 +27,7 @@
font-family: "Source Code Pro";
font-size: 14px;
margin-bottom: 2px;
background-color: transparent;
}
#code_area #line_number_area {
+129 -58
View File
@@ -14,6 +14,7 @@
#include "data/location/TokenLocation.h"
#include "data/location/TokenLocationFile.h"
#include "qt/element/QtCodeFile.h"
#include "qt/element/QtCodeSnippet.h"
#include "qt/utility/QtHighlighter.h"
#include "settings/ApplicationSettings.h"
@@ -43,14 +44,14 @@ QtCodeArea::QtCodeArea(
uint startLineNumber,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
QtCodeFile* file,
QtCodeSnippet* parent
)
: QPlainTextEdit(parent)
, m_parent(parent)
, m_fileWidget(file)
, m_maximizeButton(nullptr)
, m_startLineNumber(startLineNumber)
, m_focusedTokenId(0)
, m_isFocused(false)
, m_hoveredAnnotation(nullptr)
, m_digits(0)
{
setObjectName("code_area");
@@ -160,7 +161,7 @@ void QtCodeArea::updateLineNumberAreaWidthForDigits(int digits)
updateLineNumberAreaWidth(0);
}
void QtCodeArea::update()
void QtCodeArea::updateContent()
{
annotateText();
}
@@ -181,6 +182,42 @@ void QtCodeArea::showEvent(QShowEvent* event)
setMaximumHeight(sizeHint().height());
}
void QtCodeArea::paintEvent(QPaintEvent* event)
{
QPainter painter(viewport());
painter.fillRect(rect(), Qt::white);
QTextBlock block = firstVisibleBlock();
int top = blockBoundingGeometry(block).translated(contentOffset()).top();
int blockHeight = blockBoundingRect(block).height();
Colori color = ApplicationSettings::getInstance()->getCodeScopeColor();
Colori colorFocused = ApplicationSettings::getInstance()->getCodeActiveLinkColor();
colorFocused.a /= 2;
QColor qColor;
for (const ScopeAnnotation& scope : m_scopeAnnotations)
{
if (scope.isFocused)
{
qColor.setRgb(colorFocused.r, colorFocused.g, colorFocused.b, colorFocused.a);
}
else
{
qColor.setRgb(color.r, color.g, color.b, color.a);
}
painter.fillRect(
0, top + scope.startLine * blockHeight,
width(), (scope.endLine - scope.startLine + 1) * blockHeight,
qColor
);
}
QPlainTextEdit::paintEvent(event);
}
void QtCodeArea::enterEvent(QEvent* event)
{
if (m_maximizeButton)
@@ -196,13 +233,7 @@ void QtCodeArea::leaveEvent(QEvent* event)
m_maximizeButton->setEnabled(false);
}
if(m_isFocused)
{
MessageFocusOut(m_focusedTokenId).dispatch();
}
m_isFocused = false;
annotateText();
setHoveredAnnotation(nullptr);
}
void QtCodeArea::mouseReleaseEvent(QMouseEvent* event)
@@ -235,32 +266,22 @@ void QtCodeArea::mouseMoveEvent(QMouseEvent* event)
if (annotation && annotation->isScope)
{
annotation = nullptr;
MessageFocusOut(m_focusedTokenId).dispatch();
}
if (annotation && annotation->tokenId != m_focusedTokenId)
if (annotation != m_hoveredAnnotation)
{
if(m_isFocused)
{
MessageFocusOut(m_focusedTokenId).dispatch();
}
setHoveredAnnotation(annotation);
m_focusedTokenId = annotation->tokenId;
m_isFocused = true;
MessageFocusIn(m_focusedTokenId).dispatch();
const std::vector<std::string>& errorMessages = m_parent->getErrorMessages();
const std::vector<std::string>& errorMessages = m_fileWidget->getErrorMessages();
if (annotation && errorMessages.size() > annotation->tokenId)
{
QToolTip::showText(event->globalPos(), QString::fromStdString(m_parent->getErrorMessages()[annotation->tokenId]));
QToolTip::showText(event->globalPos(), QString::fromStdString(m_fileWidget->getErrorMessages()[annotation->tokenId]));
}
else
{
QToolTip::hideText();
}
annotateText();
}
}
@@ -288,7 +309,7 @@ void QtCodeArea::updateLineNumberArea(const QRect &rect, int dy)
void QtCodeArea::clickedMaximizeButton()
{
MessageShowFile(m_parent->getFilePath().absoluteStr(), m_startLineNumber, m_startLineNumber + blockCount() - 1).dispatch();
MessageShowFile(m_fileWidget->getFilePath().absoluteStr(), m_startLineNumber, m_startLineNumber + blockCount() - 1).dispatch();
}
void QtCodeArea::clearSelection()
@@ -298,6 +319,19 @@ void QtCodeArea::clearSelection()
setTextCursor(cursor);
}
QtCodeArea::ScopeAnnotation::ScopeAnnotation()
: startLine(0)
, endLine(0)
, tokenId(0)
, isFocused(false)
{
}
bool QtCodeArea::ScopeAnnotation::operator!=(const ScopeAnnotation& other) const
{
return (startLine != other.startLine || endLine != other.endLine || tokenId != other.tokenId || isFocused != other.isFocused);
}
const QtCodeArea::Annotation* QtCodeArea::findAnnotationForPosition(int pos) const
{
const Annotation* annotationPtr = nullptr;
@@ -325,7 +359,7 @@ void QtCodeArea::createAnnotations(std::shared_ptr<TokenLocationFile> locationFi
[&](TokenLocation* startLocation)
{
Annotation annotation;
int endLineNumber = m_startLineNumber + blockCount() - 1;
unsigned int endLineNumber = m_startLineNumber + blockCount() - 1;
if (startLocation->getLineNumber() <= endLineNumber)
{
if (startLocation->getLineNumber() < m_startLineNumber)
@@ -370,38 +404,29 @@ void QtCodeArea::createAnnotations(std::shared_ptr<TokenLocationFile> locationFi
void QtCodeArea::annotateText()
{
Colori color;
const std::vector<Id>& ids = m_parent->getActiveTokenIds();
const std::vector<std::string>& errorMessages = m_parent->getErrorMessages();
Id focusedTokenId = m_fileWidget->getFocusedTokenId();
const std::vector<Id>& ids = m_fileWidget->getActiveTokenIds();
const std::vector<std::string>& errorMessages = m_fileWidget->getErrorMessages();
QList<QTextEdit::ExtraSelection> extraSelections;
std::vector<ScopeAnnotation> scopeAnnotations;
for (const Annotation& annotation: m_annotations)
{
bool isActive = std::find(ids.begin(), ids.end(), annotation.tokenId) != ids.end();
bool isFocused = (annotation.tokenId == focusedTokenId);
if (annotation.tokenId == m_focusedTokenId && errorMessages.size())
if (&annotation == m_hoveredAnnotation && errorMessages.size())
{
color = Colori(255, 0, 0, 128);
}
else if(annotation.tokenId == m_focusedTokenId)
{
color = ApplicationSettings::getInstance()->getCodeActiveLinkColor();
}
else if (errorMessages.size())
{
color = Colori(255, 0, 0, 255);
}
else if (isActive)
else if (isActive || isFocused)
{
color = ApplicationSettings::getInstance()->getCodeActiveLinkColor();
if (annotation.isScope)
{
color.a /= 2;
}
}
else if (annotation.isScope)
{
color = ApplicationSettings::getInstance()->getCodeScopeColor();
}
else
{
@@ -411,15 +436,73 @@ void QtCodeArea::annotateText()
QTextEdit::ExtraSelection selection;
selection.format.setBackground(QColor(color.r, color.g, color.b, color.a));
ScopeAnnotation scopeAnnotation;
selection.cursor = textCursor();
selection.cursor.clearSelection();
selection.cursor.setPosition(annotation.start);
scopeAnnotation.startLine = selection.cursor.blockNumber();
selection.cursor.setPosition(annotation.end, QTextCursor::KeepAnchor);
scopeAnnotation.endLine = selection.cursor.blockNumber();
extraSelections.append(selection);
if (annotation.isScope)
{
if (isActive || isFocused)
{
scopeAnnotation.tokenId = annotation.tokenId;
if (!isActive)
{
scopeAnnotation.isFocused = isFocused;
}
scopeAnnotations.push_back(scopeAnnotation);
}
}
else
{
extraSelections.append(selection);
}
}
setExtraSelections(extraSelections);
bool needsUpdate = false;
if (scopeAnnotations.size() != m_scopeAnnotations.size())
{
needsUpdate = true;
}
else
{
for (size_t i = 0; i < scopeAnnotations.size(); i++)
{
if (scopeAnnotations[i] != m_scopeAnnotations[i])
{
needsUpdate = true;
break;
}
}
}
m_scopeAnnotations = scopeAnnotations;
if (needsUpdate)
{
viewport()->update();
}
}
void QtCodeArea::setHoveredAnnotation(const Annotation* annotation)
{
if (m_hoveredAnnotation)
{
MessageFocusOut(m_hoveredAnnotation->tokenId).dispatch();
}
m_hoveredAnnotation = annotation;
if (annotation)
{
MessageFocusIn(annotation->tokenId).dispatch();
}
}
int QtCodeArea::toTextEditPosition(int lineNumber, int columnNumber) const
@@ -452,15 +535,3 @@ int QtCodeArea::endTextEditPosition() const
return position - 1;
}
void QtCodeArea::focusToken(Id tokenId)
{
m_focusedTokenId = tokenId;
annotateText();
}
void QtCodeArea::defocusToken()
{
m_focusedTokenId = -1;
annotateText();
}
+21 -8
View File
@@ -13,6 +13,7 @@ class QPushButton;
class QResizeEvent;
class QSize;
class QtCodeFile;
class QtCodeSnippet;
class QtHighlighter;
class QWidget;
class TokenLocation;
@@ -42,7 +43,8 @@ public:
uint startLineNumber,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
QtCodeFile* file,
QtCodeSnippet* parent
);
virtual ~QtCodeArea();
@@ -55,14 +57,12 @@ public:
int lineNumberAreaWidth() const;
void updateLineNumberAreaWidthForDigits(int digits);
void update();
void focusToken(Id tokenId);
void defocusToken();
void updateContent();
protected:
virtual void resizeEvent(QResizeEvent *event);
virtual void showEvent(QShowEvent* event);
virtual void paintEvent(QPaintEvent* event);
virtual void enterEvent(QEvent* event);
virtual void leaveEvent(QEvent* event);
virtual void mouseReleaseEvent(QMouseEvent* event);
@@ -85,17 +85,30 @@ private:
bool isScope;
};
struct ScopeAnnotation
{
ScopeAnnotation();
bool operator!=(const ScopeAnnotation& other) const;
int startLine;
int endLine;
Id tokenId;
bool isFocused;
};
const Annotation* findAnnotationForPosition(int pos) const;
void createAnnotations(std::shared_ptr<TokenLocationFile> locationFile);
void annotateText();
void setHoveredAnnotation(const Annotation* annotation);
bool locationBelongsToSnippet(TokenLocation* location) const;
int toTextEditPosition(int lineNumber, int columnNumber) const;
int startTextEditPosition() const;
int endTextEditPosition() const;
QtCodeFile* m_parent;
QtCodeFile* m_fileWidget;
QWidget* m_lineNumberArea;
QtHighlighter* m_highlighter;
@@ -105,9 +118,9 @@ private:
const uint m_startLineNumber;
std::vector<Annotation> m_annotations;
std::vector<ScopeAnnotation> m_scopeAnnotations;
const Annotation* m_hoveredAnnotation;
Id m_focusedTokenId;
bool m_isFocused;
int m_digits;
};
+7 -18
View File
@@ -49,6 +49,11 @@ std::string QtCodeFile::getFileName() const
return m_filePath.fileName();
}
Id QtCodeFile::getFocusedTokenId() const
{
return m_parent->getFocusedTokenId();
}
const std::vector<Id>& QtCodeFile::getActiveTokenIds() const
{
return m_parent->getActiveTokenIds();
@@ -88,11 +93,11 @@ void QtCodeFile::addCodeSnippet(
}
}
void QtCodeFile::update()
void QtCodeFile::updateContent()
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->update();
snippet->updateContent();
}
m_title->setEnabled(m_parent->getShowMaximizeButton());
@@ -102,19 +107,3 @@ void QtCodeFile::clickedTitle()
{
MessageShowFile(m_filePath.absoluteStr(), 0, 0).dispatch();
}
void QtCodeFile::focusToken(Id tokenId)
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->focusToken(tokenId);
}
}
void QtCodeFile::defocusToken()
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
snippet->defocusToken();
}
}
+2 -3
View File
@@ -26,6 +26,7 @@ public:
const FilePath& getFilePath() const;
std::string getFileName() const;
Id getFocusedTokenId() const;
const std::vector<Id>& getActiveTokenIds() const;
const std::vector<std::string>& getErrorMessages() const;
@@ -36,9 +37,7 @@ public:
std::shared_ptr<TokenLocationFile> locationFile
);
void update();
void focusToken(Id tokenId);
void defocusToken();
void updateContent();
private slots:
void clickedTitle();
+11 -9
View File
@@ -10,6 +10,7 @@
QtCodeFileList::QtCodeFileList(QWidget* parent)
: QScrollArea(parent)
, m_showMaximizeButton(true)
, m_focusedTokenId(0)
{
m_frame = std::make_shared<QFrame>(this);
@@ -70,6 +71,11 @@ void QtCodeFileList::clearCodeSnippets()
this->verticalScrollBar()->setValue(0);
}
Id QtCodeFileList::getFocusedTokenId() const
{
return m_focusedTokenId;
}
const std::vector<Id>& QtCodeFileList::getActiveTokenIds() const
{
return m_activeTokenIds;
@@ -107,22 +113,18 @@ void QtCodeFileList::updateFiles()
{
for (std::shared_ptr<QtCodeFile> file: m_files)
{
file->update();
file->updateContent();
}
}
void QtCodeFileList::focusToken(Id tokenId)
{
for (std::shared_ptr<QtCodeFile> file: m_files)
{
file->focusToken(tokenId);
}
m_focusedTokenId = tokenId;
updateFiles();
}
void QtCodeFileList::defocusToken()
{
for (std::shared_ptr<QtCodeFile> file: m_files)
{
file->defocusToken();
}
m_focusedTokenId = 0;
updateFiles();
}
+3
View File
@@ -31,6 +31,8 @@ public:
void clearCodeSnippets();
Id getFocusedTokenId() const;
const std::vector<Id>& getActiveTokenIds() const;
void setActiveTokenIds(const std::vector<Id>& activeTokenIds);
@@ -49,6 +51,7 @@ private:
std::shared_ptr<QFrame> m_frame;
std::vector<std::shared_ptr<QtCodeFile>> m_files;
Id m_focusedTokenId;
std::vector<Id> m_activeTokenIds;
std::vector<std::string> m_errorMessages;
bool m_showMaximizeButton;
+5 -16
View File
@@ -10,11 +10,10 @@ QtCodeSnippet::QtCodeSnippet(
const std::string& title,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
QtCodeFile* file
)
: QWidget(parent)
, m_parent(parent)
, m_codeArea(std::make_shared<QtCodeArea>(startLineNumber, code, locationFile, parent))
: QWidget(file)
, m_codeArea(std::make_shared<QtCodeArea>(startLineNumber, code, locationFile, file, this))
{
setObjectName("code_snippet");
@@ -53,17 +52,7 @@ void QtCodeSnippet::updateLineNumberAreaWidthForDigits(int digits)
m_codeArea->updateLineNumberAreaWidthForDigits(digits);
}
void QtCodeSnippet::update()
void QtCodeSnippet::updateContent()
{
m_codeArea->update();
}
void QtCodeSnippet::focusToken(Id tokenId)
{
m_codeArea->focusToken(tokenId);
}
void QtCodeSnippet::defocusToken()
{
m_codeArea->defocusToken();
m_codeArea->updateContent();
}
+2 -7
View File
@@ -16,13 +16,12 @@ class QtCodeSnippet: public QWidget
Q_OBJECT
public:
QtCodeSnippet(
uint startLineNumber,
const std::string& title,
const std::string& code,
std::shared_ptr<TokenLocationFile> locationFile,
QtCodeFile* parent
QtCodeFile* file
);
virtual ~QtCodeSnippet();
@@ -31,13 +30,9 @@ public:
int lineNumberDigits() const;
void updateLineNumberAreaWidthForDigits(int digits);
void update();
void focusToken(Id tokenId);
void defocusToken();
void updateContent();
private:
QtCodeFile* m_parent; // need this?
QPushButton* m_title;
std::shared_ptr<QtCodeArea> m_codeArea;
};