diff --git a/src/app/qt/element/QtCodeArea.cpp b/src/app/qt/element/QtCodeArea.cpp index 6241ebb3..bbfc9e1a 100644 --- a/src/app/qt/element/QtCodeArea.cpp +++ b/src/app/qt/element/QtCodeArea.cpp @@ -248,6 +248,22 @@ void QtCodeArea::setIsActiveFile(bool isActiveFile) m_isActiveFile = isActiveFile; } +QRectF QtCodeArea::getFirstActiveLineRect() const +{ + int lineNumber = 0; + for (const Annotation& annotation : m_annotations) + { + if (annotation.isActive) + { + lineNumber = annotation.startLine; + break; + } + } + + QTextBlock block = document()->findBlockByLineNumber(lineNumber - m_startLineNumber); + return blockBoundingGeometry(block); +} + void QtCodeArea::resizeEvent(QResizeEvent *e) { QPlainTextEdit::resizeEvent(e); diff --git a/src/app/qt/element/QtCodeArea.h b/src/app/qt/element/QtCodeArea.h index d95511dc..d425e84a 100644 --- a/src/app/qt/element/QtCodeArea.h +++ b/src/app/qt/element/QtCodeArea.h @@ -83,6 +83,8 @@ public: void setIsActiveFile(bool isActiveFile); + QRectF getFirstActiveLineRect() const; + protected: virtual void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE; virtual void showEvent(QShowEvent* event) Q_DECL_OVERRIDE; diff --git a/src/app/qt/element/QtCodeFile.cpp b/src/app/qt/element/QtCodeFile.cpp index 1e6e7ac6..4ce23203 100644 --- a/src/app/qt/element/QtCodeFile.cpp +++ b/src/app/qt/element/QtCodeFile.cpp @@ -179,7 +179,7 @@ void QtCodeFile::addCodeSnippet( updateRefCount(refCount); } -QWidget* QtCodeFile::insertCodeSnippet( +QtCodeSnippet* QtCodeFile::insertCodeSnippet( uint startLineNumber, const std::string& title, Id titleId, @@ -229,7 +229,7 @@ QWidget* QtCodeFile::insertCodeSnippet( return snippet.get(); } -QWidget* QtCodeFile::findFirstActiveSnippet() const +QtCodeSnippet* QtCodeFile::findFirstActiveSnippet() const { if (m_locationFile) { diff --git a/src/app/qt/element/QtCodeFile.h b/src/app/qt/element/QtCodeFile.h index 013e5a56..ee4795d8 100644 --- a/src/app/qt/element/QtCodeFile.h +++ b/src/app/qt/element/QtCodeFile.h @@ -49,7 +49,7 @@ public: int refCount ); - QWidget* insertCodeSnippet( + QtCodeSnippet* insertCodeSnippet( uint startLineNumber, const std::string& title, Id titleId, @@ -58,7 +58,7 @@ public: int refCount ); - QWidget* findFirstActiveSnippet() const; + QtCodeSnippet* findFirstActiveSnippet() const; bool openCollapsedActiveSnippet() const; void updateContent(); diff --git a/src/app/qt/element/QtCodeFileList.cpp b/src/app/qt/element/QtCodeFileList.cpp index 2e2ff24a..c71a7900 100644 --- a/src/app/qt/element/QtCodeFileList.cpp +++ b/src/app/qt/element/QtCodeFileList.cpp @@ -9,6 +9,7 @@ #include "data/location/TokenLocationFile.h" #include "qt/element/QtCodeFile.h" +#include "qt/element/QtCodeSnippet.h" QtCodeFileList::QtCodeFileList(QWidget* parent) : QScrollArea(parent) @@ -27,7 +28,7 @@ QtCodeFileList::QtCodeFileList(QWidget* parent) setWidgetResizable(true); setWidget(m_frame.get()); - connect(this, SIGNAL(shouldScrollToSnippet(QWidget*)), this, SLOT(scrollToSnippet(QWidget*)), Qt::QueuedConnection); + connect(this, SIGNAL(shouldScrollToSnippet(QtCodeSnippet*)), this, SLOT(scrollToSnippet(QtCodeSnippet*)), Qt::QueuedConnection); } QtCodeFileList::~QtCodeFileList() @@ -53,7 +54,7 @@ void QtCodeFileList::addCodeSnippet( if (insert) { - QWidget* snippet = file->insertCodeSnippet(startLineNumber, title, titleId, code, locationFile, refCount); + QtCodeSnippet* snippet = file->insertCodeSnippet(startLineNumber, title, titleId, code, locationFile, refCount); emit shouldScrollToSnippet(snippet); } else @@ -110,18 +111,18 @@ bool QtCodeFileList::scrollToFirstActiveSnippet() { updateFiles(); - QWidget* widget = nullptr; + QtCodeSnippet* snippet = nullptr; for (std::shared_ptr file: m_files) { - widget = file->findFirstActiveSnippet(); - if (widget) + snippet = file->findFirstActiveSnippet(); + if (snippet) { - if (!widget->isVisible()) + if (!snippet->isVisible()) { file->clickedSnippetButton(); } - emit shouldScrollToSnippet(widget); + emit shouldScrollToSnippet(snippet); return true; } } @@ -152,9 +153,9 @@ void QtCodeFileList::defocusTokenIds() updateFiles(); } -void QtCodeFileList::scrollToSnippet(QWidget* widget) +void QtCodeFileList::scrollToSnippet(QtCodeSnippet* snippet) { - this->ensureWidgetVisibleAnimated(widget); + this->ensureWidgetVisibleAnimated(snippet, snippet->getFirstActiveLineRect()); } QtCodeFile* QtCodeFileList::getFile(std::shared_ptr locationFile) @@ -191,7 +192,7 @@ void QtCodeFileList::updateFiles() } } -void QtCodeFileList::ensureWidgetVisibleAnimated(QWidget *childWidget, int xmargin, int ymargin) +void QtCodeFileList::ensureWidgetVisibleAnimated(QWidget *childWidget, QRectF rect) { if (!widget()->isAncestorOf(childWidget)) { @@ -205,54 +206,21 @@ void QtCodeFileList::ensureWidgetVisibleAnimated(QWidget *childWidget, int xmarg : QRect(childWidget->mapTo(widget(), QPoint(0, 0)), childWidget->size()); const QRect visibleRect(-widget()->pos(), viewport()->size()); - if (visibleRect.contains(focusRect)) + if (rect.height() > 0) { - return; + focusRect = QRect(childWidget->mapTo(widget(), rect.topLeft().toPoint()), rect.size().toSize()); + focusRect.adjust(0, 0, 0, 100); } - focusRect.adjust(-xmargin, -ymargin, xmargin, ymargin); + QScrollBar* scrollBar = verticalScrollBar(); + int value = focusRect.center().y() - visibleRect.center().y(); - QScrollBar* scrollBar = nullptr; - int value = 0; - - if (focusRect.width() > visibleRect.width()) - { - scrollBar = horizontalScrollBar(); - value = focusRect.center().x() - viewport()->width() / 2; - } - else if (focusRect.right() > visibleRect.right()) - { - scrollBar = horizontalScrollBar(); - value = focusRect.right() - viewport()->width(); - } - else if (focusRect.left() < visibleRect.left()) - { - scrollBar = horizontalScrollBar(); - value = focusRect.left(); - } - - if (focusRect.height() > visibleRect.height()) - { - scrollBar = verticalScrollBar(); - value = focusRect.center().y() - viewport()->height() / 2; - } - else if (focusRect.bottom() > visibleRect.bottom()) - { - scrollBar = verticalScrollBar(); - value = focusRect.bottom() - viewport()->height(); - } - else if (focusRect.top() < visibleRect.top()) - { - scrollBar = verticalScrollBar(); - value = focusRect.top(); - } - - if (scrollBar) + if (scrollBar && value != 0) { QPropertyAnimation* anim = new QPropertyAnimation(scrollBar, "value"); anim->setDuration(500); anim->setStartValue(scrollBar->value()); - anim->setEndValue(value); + anim->setEndValue(scrollBar->value() + value); anim->setEasingCurve(QEasingCurve::InOutQuad); anim->start(); } diff --git a/src/app/qt/element/QtCodeFileList.h b/src/app/qt/element/QtCodeFileList.h index c68cb5a8..6b035860 100644 --- a/src/app/qt/element/QtCodeFileList.h +++ b/src/app/qt/element/QtCodeFileList.h @@ -11,6 +11,7 @@ #include "utility/types.h" class QtCodeFile; +class QtCodeSnippet; class TokenLocationFile; class QtCodeFileList @@ -19,7 +20,7 @@ class QtCodeFileList Q_OBJECT signals: - void shouldScrollToSnippet(QWidget* widget); + void shouldScrollToSnippet(QtCodeSnippet* widget); public: QtCodeFileList(QWidget* parent = 0); @@ -58,14 +59,14 @@ public: void defocusTokenIds(); private slots: - void scrollToSnippet(QWidget* widget); + void scrollToSnippet(QtCodeSnippet* snippet); private: QtCodeFile* getFile(std::shared_ptr locationFile); void updateFiles(); - void ensureWidgetVisibleAnimated(QWidget *childWidget, int xmargin = 50, int ymargin = 50); + void ensureWidgetVisibleAnimated(QWidget *childWidget, QRectF rect); std::shared_ptr m_frame; std::vector> m_files; diff --git a/src/app/qt/element/QtCodeSnippet.cpp b/src/app/qt/element/QtCodeSnippet.cpp index 3985547d..72f5f418 100644 --- a/src/app/qt/element/QtCodeSnippet.cpp +++ b/src/app/qt/element/QtCodeSnippet.cpp @@ -145,6 +145,11 @@ void QtCodeSnippet::setIsActiveFile(bool isActiveFile) m_codeArea->setIsActiveFile(isActiveFile); } +QRectF QtCodeSnippet::getFirstActiveLineRect() const +{ + return m_codeArea->getFirstActiveLineRect(); +} + void QtCodeSnippet::contextMenuEvent(QContextMenuEvent* event) { QMenu menu(this); diff --git a/src/app/qt/element/QtCodeSnippet.h b/src/app/qt/element/QtCodeSnippet.h index 1762af73..b9697e03 100644 --- a/src/app/qt/element/QtCodeSnippet.h +++ b/src/app/qt/element/QtCodeSnippet.h @@ -44,6 +44,8 @@ public: void setIsActiveFile(bool isActiveFile); + QRectF getFirstActiveLineRect() const; + protected: virtual void contextMenuEvent(QContextMenuEvent* event) Q_DECL_OVERRIDE; diff --git a/src/app/qt/view/QtCodeView.cpp b/src/app/qt/view/QtCodeView.cpp index 0dcdc242..47b671e5 100644 --- a/src/app/qt/view/QtCodeView.cpp +++ b/src/app/qt/view/QtCodeView.cpp @@ -12,11 +12,12 @@ QtCodeView::QtCodeView(ViewLayout* viewLayout) : CodeView(viewLayout) , m_refreshViewFunctor(std::bind(&QtCodeView::doRefreshView, this)) , m_showCodeSnippetsFunctor(std::bind(&QtCodeView::doShowCodeSnippets, this, std::placeholders::_1)) - , m_addCodeSnippetsFunctor(std::bind(&QtCodeView::doAddCodeSnippets, this, std::placeholders::_1)) + , m_addCodeSnippetsFunctor(std::bind(&QtCodeView::doAddCodeSnippets, this, std::placeholders::_1, std::placeholders::_2)) , m_showCodeFileFunctor(std::bind(&QtCodeView::doShowCodeFile, this, std::placeholders::_1)) , m_doShowFirstActiveSnippetFunctor(std::bind(&QtCodeView::doShowFirstActiveSnippet, this)) , m_focusTokenIdsFunctor(std::bind(&QtCodeView::doFocusTokenIds, this, std::placeholders::_1)) , m_defocusTokenIdsFunctor(std::bind(&QtCodeView::doDefocusTokenIds, this)) + , m_isExpanding(false) { m_widget = new QtCodeFileList(); setStyleSheet(); @@ -55,9 +56,9 @@ void QtCodeView::showCodeSnippets(const std::vector& snippets m_showCodeSnippetsFunctor(snippets); } -void QtCodeView::addCodeSnippets(const std::vector& snippets) +void QtCodeView::addCodeSnippets(const std::vector& snippets, bool insert) { - m_addCodeSnippetsFunctor(snippets); + m_addCodeSnippetsFunctor(snippets, insert); } void QtCodeView::showCodeFile(const CodeSnippetParams& params) @@ -117,7 +118,7 @@ void QtCodeView::doShowCodeSnippets(const std::vector& snippe setStyleSheet(); // so property "isLast" of QtCodeSnippet is computed correctly } -void QtCodeView::doAddCodeSnippets(const std::vector& snippets) +void QtCodeView::doAddCodeSnippets(const std::vector& snippets, bool insert) { for (const CodeSnippetParams& params : snippets) { @@ -129,11 +130,17 @@ void QtCodeView::doAddCodeSnippets(const std::vector& snippet params.locationFile, params.refCount, params.modificationTime, - true + insert ); } setStyleSheet(); // so property "isLast" of QtCodeSnippet is computed correctly + + if (m_isExpanding) + { + m_widget->scrollToFirstActiveSnippet(); + m_isExpanding = false; + } } void QtCodeView::doShowCodeFile(const CodeSnippetParams& params) @@ -148,6 +155,7 @@ void QtCodeView::doShowFirstActiveSnippet() if (!m_widget->scrollToFirstActiveSnippet()) { m_widget->expandActiveSnippetFile(); + m_isExpanding = true; } } diff --git a/src/app/qt/view/QtCodeView.h b/src/app/qt/view/QtCodeView.h index 4f343637..2fe022f7 100644 --- a/src/app/qt/view/QtCodeView.h +++ b/src/app/qt/view/QtCodeView.h @@ -30,7 +30,7 @@ public: virtual void setErrorMessages(const std::vector& errorMessages); virtual void showCodeSnippets(const std::vector& snippets); - virtual void addCodeSnippets(const std::vector& snippets); + virtual void addCodeSnippets(const std::vector& snippets, bool insert); virtual void showCodeFile(const CodeSnippetParams& params); virtual void showFirstActiveSnippet(); @@ -42,7 +42,7 @@ private: void doRefreshView(); void doShowCodeSnippets(const std::vector& snippets); - void doAddCodeSnippets(const std::vector& snippets); + void doAddCodeSnippets(const std::vector& snippets, bool insert); void doShowCodeFile(const CodeSnippetParams& params); void doShowFirstActiveSnippet(); @@ -54,7 +54,7 @@ private: QtThreadedFunctor<> m_refreshViewFunctor; QtThreadedFunctor&> m_showCodeSnippetsFunctor; - QtThreadedFunctor&> m_addCodeSnippetsFunctor; + QtThreadedFunctor&, bool> m_addCodeSnippetsFunctor; QtThreadedFunctor m_showCodeFileFunctor; QtThreadedFunctor<> m_doShowFirstActiveSnippetFunctor; QtThreadedFunctor&> m_focusTokenIdsFunctor; @@ -64,6 +64,8 @@ private: std::vector m_activeTokenIds; std::vector m_errorMessages; + + bool m_isExpanding; }; # endif // QT_CODE_VIEW_H diff --git a/src/lib/component/controller/CodeController.cpp b/src/lib/component/controller/CodeController.cpp index f3ad6981..31e0055b 100644 --- a/src/lib/component/controller/CodeController.cpp +++ b/src/lib/component/controller/CodeController.cpp @@ -155,12 +155,12 @@ void CodeController::handleMessage(MessageShowScope* message) return; } - getView()->addCodeSnippets(snippets); + getView()->addCodeSnippets(snippets, true); } void CodeController::handleMessage(MessageShowSnippets* message) { - getView()->addCodeSnippets(getSnippetsForActiveTokenLocationsInFile(message->locationFile)); + getView()->addCodeSnippets(getSnippetsForActiveTokenLocationsInFile(message->locationFile), false); } CodeView* CodeController::getView() diff --git a/src/lib/component/view/CodeView.h b/src/lib/component/view/CodeView.h index 98e85acb..721037c3 100644 --- a/src/lib/component/view/CodeView.h +++ b/src/lib/component/view/CodeView.h @@ -47,7 +47,7 @@ public: virtual void setErrorMessages(const std::vector& errorMessages) = 0; virtual void showCodeSnippets(const std::vector& snippets) = 0; - virtual void addCodeSnippets(const std::vector& snippets) = 0; + virtual void addCodeSnippets(const std::vector& snippets, bool insert) = 0; virtual void showCodeFile(const CodeSnippetParams& params) = 0; virtual void showFirstActiveSnippet() = 0;