ui: draw scope annotations in CodeView using one big rectangle
And refactored QtCodeFile classes.
This commit is contained in:
@@ -27,6 +27,7 @@
|
||||
font-family: "Source Code Pro";
|
||||
font-size: 14px;
|
||||
margin-bottom: 2px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
#code_area #line_number_area {
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user