From a70a9009ccbf46b934c1787cb2f244fa5a787bfc Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Fri, 4 Jul 2014 15:33:51 +0200 Subject: [PATCH] ui: Improved scrolling and layouting in QtCodeView and colored locations of active TokenId differently --- bin/app/data/ApplicationSettings.xml | 1 + bin/app/data/src/header.h | 4 ++ bin/app/data/src/main.cpp | 22 ++++++++++- src/app/qt/element/QtCodeFile.cpp | 9 +++-- src/app/qt/element/QtCodeFile.h | 6 ++- src/app/qt/element/QtCodeSnippet.cpp | 38 +++++++++++++++++-- src/app/qt/element/QtCodeSnippet.h | 6 ++- src/app/qt/view/QtCodeView.cpp | 34 ++++++++++------- src/app/qt/view/QtCodeView.h | 8 ++-- src/lib/ApplicationSettings.cpp | 10 +++++ src/lib/ApplicationSettings.h | 3 ++ .../component/controller/CodeController.cpp | 12 ++++-- src/lib/component/view/CodeView.cpp | 5 +++ src/lib/component/view/CodeView.h | 15 +++++++- src/lib/data/location/TokenLocationFile.h | 2 +- 15 files changed, 142 insertions(+), 33 deletions(-) create mode 100644 bin/app/data/src/header.h diff --git a/bin/app/data/ApplicationSettings.xml b/bin/app/data/ApplicationSettings.xml index 130a768d..940fef6d 100644 --- a/bin/app/data/ApplicationSettings.xml +++ b/bin/app/data/ApplicationSettings.xml @@ -5,5 +5,6 @@ Courier 12 255 255 0 100 + 0 255 0 100 diff --git a/bin/app/data/src/header.h b/bin/app/data/src/header.h new file mode 100644 index 00000000..84af058e --- /dev/null +++ b/bin/app/data/src/header.h @@ -0,0 +1,4 @@ +int main(); +void foo(); +int sum(int a, int b); +int diff(int a, int b); diff --git a/bin/app/data/src/main.cpp b/bin/app/data/src/main.cpp index 20d59a79..825e2010 100644 --- a/bin/app/data/src/main.cpp +++ b/bin/app/data/src/main.cpp @@ -1,5 +1,9 @@ +#include "header.h" + int main(); void foo(); +int sum(int a, int b); +int diff(int a, int b); int main() { @@ -9,7 +13,23 @@ int main() return 0; } +int sum(int a, int b); + +int diff(int a, int b); + void foo() { std::string foo = "bar"; -} \ No newline at end of file +} + +int diff(int a, int b); + +int sum(int a, int b) +{ + return a + b; +} + +int diff(int a, int b) +{ + return a - b; +} diff --git a/src/app/qt/element/QtCodeFile.cpp b/src/app/qt/element/QtCodeFile.cpp index 0efb9e8c..3dd2ca2b 100644 --- a/src/app/qt/element/QtCodeFile.cpp +++ b/src/app/qt/element/QtCodeFile.cpp @@ -13,6 +13,7 @@ QtCodeFile::QtCodeFile(QtCodeView* parentView, const std::string& fileName, QWid QVBoxLayout* layout = new QVBoxLayout(this); layout->setMargin(0); layout->setSpacing(2); + layout->setAlignment(Qt::AlignTop); setLayout(layout); QLabel* label = new QLabel(fileName.c_str(), this); @@ -20,6 +21,7 @@ QtCodeFile::QtCodeFile(QtCodeView* parentView, const std::string& fileName, QWid label->setStyleSheet("background-color: #E1E1E1; padding: 3px;"); label->setFixedWidth(metrics.boundingRect(fileName.c_str()).width() + 12); + label->setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); layout->addWidget(label); } @@ -32,10 +34,11 @@ const std::string& QtCodeFile::getFileName() const return m_fileName; } -void QtCodeFile::addCodeSnippet(const std::string& str, const TokenLocationFile& locationFile, int startLineNumber) -{ +void QtCodeFile::addCodeSnippet( + const std::string& str, const TokenLocationFile& locationFile, int startLineNumber, Id activeTokenId +){ std::shared_ptr snippet = - std::make_shared(m_parentView, str, locationFile, startLineNumber, this); + std::make_shared(m_parentView, str, locationFile, startLineNumber, activeTokenId, this); layout()->addWidget(snippet.get()); m_snippets.push_back(snippet); } diff --git a/src/app/qt/element/QtCodeFile.h b/src/app/qt/element/QtCodeFile.h index 5935f7ef..26936a84 100644 --- a/src/app/qt/element/QtCodeFile.h +++ b/src/app/qt/element/QtCodeFile.h @@ -7,6 +7,8 @@ #include +#include "utility/types.h" + class QtCodeSnippet; class QtCodeView; class TokenLocationFile; @@ -19,7 +21,9 @@ public: const std::string& getFileName() const; - void addCodeSnippet(const std::string& str, const TokenLocationFile& locationFile, int startLineNumber); + void addCodeSnippet( + const std::string& str, const TokenLocationFile& locationFile, int startLineNumber, Id activeTokenId + ); private: QtCodeView* m_parentView; diff --git a/src/app/qt/element/QtCodeSnippet.cpp b/src/app/qt/element/QtCodeSnippet.cpp index b5e7bfe4..9751927a 100644 --- a/src/app/qt/element/QtCodeSnippet.cpp +++ b/src/app/qt/element/QtCodeSnippet.cpp @@ -36,21 +36,26 @@ QtCodeSnippet::QtCodeSnippet( const std::string& code, const TokenLocationFile& locationFile, int startLineNumber, + Id activeTokenId, QWidget *parent ) : QPlainTextEdit(parent) , m_parentView(parentView) , m_startLineNumber(startLineNumber) + , m_activeTokenId(activeTokenId) { m_lineNumberArea = new LineNumberArea(this); setReadOnly(true); setFrameStyle(QFrame::NoFrame); + setSizePolicy(sizePolicy().horizontalPolicy(), QSizePolicy::Fixed); + setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); + setLineWrapMode(QPlainTextEdit::NoWrap); QFont font; font.setFamily(ApplicationSettings::getInstance()->getCodeFontName().c_str()); - font.setFixedPitch(true); font.setPointSize(ApplicationSettings::getInstance()->getCodeFontSize()); + font.setFixedPitch(true); setFont(font); int tabWidth = ApplicationSettings::getInstance()->getCodeTabWidth(); @@ -58,7 +63,14 @@ QtCodeSnippet::QtCodeSnippet( setTabStopWidth(tabWidth * metrics.width(' ')); m_highlighter = new QtHighlighter(document()); - setPlainText(QString::fromUtf8(code.c_str())); + + std::string displayCode = code; + if (*code.rbegin() == '\n') + { + displayCode.pop_back(); + } + + setPlainText(QString::fromUtf8(displayCode.c_str())); annotateText(locationFile); connect(this, SIGNAL(blockCountChanged(int)), this, SLOT(updateLineNumberAreaWidth(int))); @@ -66,6 +78,8 @@ QtCodeSnippet::QtCodeSnippet( connect(this, SIGNAL(cursorPositionChanged()), this, SLOT(clickTokenLocation())); connect(this, SIGNAL(selectionChanged()), this, SLOT(clearSelection())); + setMaximumHeight(sizeHint().height()); + updateLineNumberAreaWidth(0); } @@ -73,6 +87,13 @@ QtCodeSnippet::~QtCodeSnippet() { } +QSize QtCodeSnippet::sizeHint() const +{ + int width = lineNumberAreaWidth() + document()->size().width(); + int height = (document()->size().height() + 1) * QFontMetrics(font()).lineSpacing(); + return QSize(width, height); +} + void QtCodeSnippet::lineNumberAreaPaintEvent(QPaintEvent *event) { QPainter painter(m_lineNumberArea); @@ -99,7 +120,7 @@ void QtCodeSnippet::lineNumberAreaPaintEvent(QPaintEvent *event) } } -int QtCodeSnippet::lineNumberAreaWidth() +int QtCodeSnippet::lineNumberAreaWidth() const { int digits = 1; int max = qMax(1, m_startLineNumber + blockCount()); @@ -138,7 +159,16 @@ void QtCodeSnippet::annotateText(const TokenLocationFile& locationFile) QTextEdit::ExtraSelection selection; - Colori color = ApplicationSettings::getInstance()->getCodeLinkColor(); + Colori color; + if (location->getTokenId() == m_activeTokenId) + { + color = ApplicationSettings::getInstance()->getCodeActiveLinkColor(); + } + else + { + color = ApplicationSettings::getInstance()->getCodeLinkColor(); + } + selection.format.setBackground(QColor(color.r, color.g, color.b, color.a)); selection.cursor = textCursor(); diff --git a/src/app/qt/element/QtCodeSnippet.h b/src/app/qt/element/QtCodeSnippet.h index 9b755e12..5ed777a6 100644 --- a/src/app/qt/element/QtCodeSnippet.h +++ b/src/app/qt/element/QtCodeSnippet.h @@ -40,12 +40,15 @@ public: const std::string& code, const TokenLocationFile& locationFile, int startLineNumber, + Id activeTokenId, QWidget *parent = 0 ); virtual ~QtCodeSnippet(); + QSize sizeHint() const; + void lineNumberAreaPaintEvent(QPaintEvent *event); - int lineNumberAreaWidth(); + int lineNumberAreaWidth() const; void annotateText(const TokenLocationFile& locationFile); @@ -73,6 +76,7 @@ private: QWidget *m_lineNumberArea; const int m_startLineNumber; + const Id m_activeTokenId; std::vector m_annotations; }; diff --git a/src/app/qt/view/QtCodeView.cpp b/src/app/qt/view/QtCodeView.cpp index c0a22a88..5cc0f281 100644 --- a/src/app/qt/view/QtCodeView.cpp +++ b/src/app/qt/view/QtCodeView.cpp @@ -1,7 +1,8 @@ #include "qt/view/QtCodeView.h" -#include -#include +#include +#include +#include #include "data/location/TokenLocationFile.h" #include "qt/element/QtCodeFile.h" @@ -13,7 +14,7 @@ QtCodeView::QtCodeView(ViewLayout* viewLayout) : CodeView(viewLayout) , m_clearCodeSnippetsFunctor(std::bind(&QtCodeView::doClearCodeSnippets, this)) - , m_addCodeSnippetFunctor(std::bind(&QtCodeView::doAddCodeSnippet, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)) + , m_addCodeSnippetFunctor(std::bind(&QtCodeView::doAddCodeSnippet, this, std::placeholders::_1)) { } @@ -23,7 +24,7 @@ QtCodeView::~QtCodeView() void QtCodeView::createWidgetWrapper() { - setWidgetWrapper(std::make_shared(std::make_shared())); + setWidgetWrapper(std::make_shared(std::make_shared())); } void QtCodeView::initGui() @@ -31,15 +32,22 @@ void QtCodeView::initGui() QWidget* widget = QtWidgetWrapper::getWidgetOfView(this); utility::setWidgetBackgroundColor(widget, Colori(255, 125, 0, 255)); - QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); - layout->setSpacing(3); + QScrollArea* scroll = dynamic_cast(widget); + m_frame = std::make_shared(scroll); + + QVBoxLayout* layout = new QVBoxLayout(m_frame.get()); + layout->setSpacing(10); layout->setContentsMargins(3, 3, 3, 3); - widget->setLayout(layout); + layout->setAlignment(Qt::AlignTop); + m_frame->setLayout(layout); + + scroll->setWidgetResizable(true); + scroll->setWidget(m_frame.get()); } -void QtCodeView::addCodeSnippet(const std::string& str, const TokenLocationFile& locationFile, int startLineNumber) +void QtCodeView::addCodeSnippet(const CodeSnippetParams params) { - m_addCodeSnippetFunctor(str, locationFile, startLineNumber); + m_addCodeSnippetFunctor(params); } void QtCodeView::clearCodeSnippets() @@ -53,9 +61,9 @@ void QtCodeView::activateToken(Id tokenId) const message.dispatch(); } -void QtCodeView::doAddCodeSnippet(const std::string& str, const TokenLocationFile& locationFile, int startLineNumber) +void QtCodeView::doAddCodeSnippet(const CodeSnippetParams params) { - std::string fileName = FileSystem::fileName(locationFile.getFilePath()); + std::string fileName = FileSystem::fileName(params.locationFile.getFilePath()); QtCodeFile* file = nullptr; for (std::shared_ptr filePtr : m_files) @@ -74,10 +82,10 @@ void QtCodeView::doAddCodeSnippet(const std::string& str, const TokenLocationFil m_files.push_back(filePtr); file = filePtr.get(); - widget->layout()->addWidget(file); + m_frame->layout()->addWidget(file); } - file->addCodeSnippet(str, locationFile, startLineNumber); + file->addCodeSnippet(params.code, params.locationFile, params.startLineNumber, params.activeTokenId); } void QtCodeView::doClearCodeSnippets() diff --git a/src/app/qt/view/QtCodeView.h b/src/app/qt/view/QtCodeView.h index 14815092..7fc82402 100644 --- a/src/app/qt/view/QtCodeView.h +++ b/src/app/qt/view/QtCodeView.h @@ -8,6 +8,7 @@ #include "qt/utility/QtThreadedFunctor.h" #include "utility/types.h" +class QFrame; class QtCodeFile; class QtCodeView: public CodeView @@ -21,19 +22,20 @@ public: virtual void initGui(); // CodeView implementation - virtual void addCodeSnippet(const std::string& str, const TokenLocationFile& locationFile, int startLineNumber); + virtual void addCodeSnippet(const CodeSnippetParams params); virtual void clearCodeSnippets(); void activateToken(Id tokenId) const; private: - void doAddCodeSnippet(const std::string& str, const TokenLocationFile& locationFile, int startLineNumber); + void doAddCodeSnippet(const CodeSnippetParams params); void doClearCodeSnippets(); + std::shared_ptr m_frame; std::vector > m_files; QtThreadedFunctor m_clearCodeSnippetsFunctor; - QtThreadedFunctor m_addCodeSnippetFunctor; + QtThreadedFunctor m_addCodeSnippetFunctor; }; # endif // QT_CODE_VIEW_H diff --git a/src/lib/ApplicationSettings.cpp b/src/lib/ApplicationSettings.cpp index 426889dc..62b92441 100644 --- a/src/lib/ApplicationSettings.cpp +++ b/src/lib/ApplicationSettings.cpp @@ -58,6 +58,16 @@ void ApplicationSettings::setCodeLinkColor(Colori codeLinkColor) setValue("code/LinkColor", codeLinkColor.toString()); } +Colori ApplicationSettings::getCodeActiveLinkColor() const +{ + return Colori::fromString(getValue("code/ActiveLinkColor", Colori(0, 255, 0, 100).toString())); +} + +void ApplicationSettings::setCodeActiveLinkColor(Colori codeLinkColor) +{ + setValue("code/ActiveLinkColor", codeLinkColor.toString()); +} + ApplicationSettings::ApplicationSettings() { } diff --git a/src/lib/ApplicationSettings.h b/src/lib/ApplicationSettings.h index 8f7e14fd..9a28fdd2 100644 --- a/src/lib/ApplicationSettings.h +++ b/src/lib/ApplicationSettings.h @@ -25,6 +25,9 @@ public: Colori getCodeLinkColor() const; void setCodeLinkColor(Colori codeLinkColor); + Colori getCodeActiveLinkColor() const; + void setCodeActiveLinkColor(Colori codeLinkColor); + private: ApplicationSettings(); ApplicationSettings(const ApplicationSettings&); diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp index 22053c64..2a3e8537 100644 --- a/src/lib/component/controller/CodeController.cpp +++ b/src/lib/component/controller/CodeController.cpp @@ -29,6 +29,7 @@ void CodeController::setActiveTokenId(Id id) collection.forEachTokenLocation([&] (TokenLocation* tokenLocation) -> void { if (tokenLocation->isStartTokenLocation()) { + CodeView::CodeSnippetParams params; const std::string filePath = tokenLocation->getFilePath(); std::shared_ptr textAccess = TextAccess::createFromFile(filePath); @@ -37,14 +38,17 @@ void CodeController::setActiveTokenId(Id id) textAccess->getLineCount(), tokenLocation->getEndTokenLocation()->getLineNumber() + lineRadius ); - std::string text; for (std::string line: textAccess->getLines(firstLineNumber, lastLineNumber)) { - text += line; + params.code += line; } - TokenLocationFile tokenLocationFile = m_locationAccess->getTokenLocationsForLinesInFile(filePath, firstLineNumber, lastLineNumber); - getView()->addCodeSnippet(text, tokenLocationFile, firstLineNumber); + params.startLineNumber = firstLineNumber; + params.locationFile = + m_locationAccess->getTokenLocationsForLinesInFile(filePath, firstLineNumber, lastLineNumber); + params.activeTokenId = id; + + getView()->addCodeSnippet(params); } }); } diff --git a/src/lib/component/view/CodeView.cpp b/src/lib/component/view/CodeView.cpp index 3d69651f..52c1334c 100644 --- a/src/lib/component/view/CodeView.cpp +++ b/src/lib/component/view/CodeView.cpp @@ -2,6 +2,11 @@ #include "component/controller/CodeController.h" +CodeView::CodeSnippetParams::CodeSnippetParams() + : locationFile("") +{ +} + CodeView::CodeView(ViewLayout* viewLayout) : View(viewLayout, Vec2i(100, 100)) { diff --git a/src/lib/component/view/CodeView.h b/src/lib/component/view/CodeView.h index bcce8e6f..97ee9d77 100644 --- a/src/lib/component/view/CodeView.h +++ b/src/lib/component/view/CodeView.h @@ -2,19 +2,30 @@ #define CODE_VIEW_H #include "component/view/View.h" +#include "data/location/TokenLocationFile.h" +#include "utility/types.h" class CodeController; -class TokenLocationFile; class CodeView: public View { public: + struct CodeSnippetParams + { + CodeSnippetParams(); + + std::string code; + TokenLocationFile locationFile; + int startLineNumber; + Id activeTokenId; + }; + CodeView(ViewLayout* viewLayout); virtual ~CodeView(); virtual std::string getName() const; - virtual void addCodeSnippet(const std::string& str, const TokenLocationFile& locationFile, int startLineNumber) = 0; + virtual void addCodeSnippet(const CodeSnippetParams params) = 0; virtual void clearCodeSnippets() = 0; private: diff --git a/src/lib/data/location/TokenLocationFile.h b/src/lib/data/location/TokenLocationFile.h index 5757483c..cb82e8ff 100644 --- a/src/lib/data/location/TokenLocationFile.h +++ b/src/lib/data/location/TokenLocationFile.h @@ -44,7 +44,7 @@ private: TokenLocationLine* createTokenLocationLine(unsigned int lineNumber); std::map > m_lines; - const std::string m_filePath; + std::string m_filePath; }; std::ostream& operator<<(std::ostream& ostream, const TokenLocationFile& file);