From 1db248a34eec9a34ee6a02b7f854627f0fa8adf6 Mon Sep 17 00:00:00 2001 From: Eberhard Graether Date: Sun, 22 Jul 2018 19:40:01 +0200 Subject: [PATCH] ui: scroll code horizontally to active sourcelocations --- src/lib_gui/qt/element/QtCodeArea.cpp | 95 +++++++++++++++++++++ src/lib_gui/qt/element/QtCodeArea.h | 3 + src/lib_gui/qt/element/QtCodeField.cpp | 12 +-- src/lib_gui/qt/element/QtCodeFileList.cpp | 3 + src/lib_gui/qt/element/QtCodeFileSingle.cpp | 2 + src/lib_gui/qt/element/QtCodeSnippet.cpp | 7 ++ src/lib_gui/qt/element/QtCodeSnippet.h | 2 + 7 files changed, 116 insertions(+), 8 deletions(-) diff --git a/src/lib_gui/qt/element/QtCodeArea.cpp b/src/lib_gui/qt/element/QtCodeArea.cpp index 77788c35..839ecf4c 100644 --- a/src/lib_gui/qt/element/QtCodeArea.cpp +++ b/src/lib_gui/qt/element/QtCodeArea.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -372,6 +373,21 @@ Id QtCodeArea::getLocationIdOfFirstActiveScopeLocation(Id tokenId) const return 0; } +Id QtCodeArea::getLocationIdOfFirstHighlightedLocation() const +{ + for (const Annotation& annotation : m_annotations) + { + if ((annotation.locationType == LocationType::LOCATION_TOKEN && annotation.isActive) || + annotation.locationType == LocationType::LOCATION_FULLTEXT_SEARCH || + annotation.locationType == LocationType::LOCATION_ERROR) + { + return annotation.locationId; + } + } + + return 0; +} + size_t QtCodeArea::getActiveLocationCount() const { uint count = 0; @@ -475,6 +491,85 @@ void QtCodeArea::clearScreenMatches() } } +void QtCodeArea::ensureLocationIdVisible(Id locationId, int parentWidth, bool animated) +{ + QScrollBar* scrollBar = horizontalScrollBar(); + if (!scrollBar || scrollBar->minimum() == scrollBar->maximum()) + { + return; + } + + const int oldValue = scrollBar->value(); + scrollBar->setValue(scrollBar->minimum()); + + const Annotation* annotationPtr = nullptr; + for (const Annotation& annotation : m_annotations) + { + if (annotation.locationId == locationId) + { + annotationPtr = &annotation; + break; + } + } + + if (!annotationPtr) + { + return; + } + + std::vector rects = getCursorRectsForAnnotation(*annotationPtr); + QRect boundingRect; + for (QRect rect : rects) + { + if (boundingRect.width()) + { + boundingRect = boundingRect.united(rect); + } + else + { + boundingRect = rect; + } + } + + if (!boundingRect.width()) + { + return; + } + + boundingRect.adjust(-50, 0, 50, 0); + + int totalWidth = sizeHint().width() - lineNumberAreaWidth(); + int visibleWidth = parentWidth - lineNumberAreaWidth(); + + int targetWidth = 0; + if (boundingRect.right() > visibleWidth) + { + targetWidth = boundingRect.right() - visibleWidth; + + if (targetWidth > boundingRect.left()) + { + targetWidth = boundingRect.left(); + } + } + + const double percentTarget = double(targetWidth) / (totalWidth - visibleWidth); + const int newValue = (scrollBar->maximum() - scrollBar->minimum()) * percentTarget + scrollBar->minimum(); + + if (animated && ApplicationSettings::getInstance()->getUseAnimations()) + { + QPropertyAnimation* anim = new QPropertyAnimation(scrollBar, "value"); + anim->setDuration(300); + anim->setStartValue(oldValue); + anim->setEndValue(newValue); + anim->setEasingCurve(QEasingCurve::InOutQuad); + anim->start(); + } + else + { + scrollBar->setValue(newValue); + } +} + void QtCodeArea::resizeEvent(QResizeEvent *e) { QPlainTextEdit::resizeEvent(e); diff --git a/src/lib_gui/qt/element/QtCodeArea.h b/src/lib_gui/qt/element/QtCodeArea.h index b39766f7..f2601f6e 100644 --- a/src/lib_gui/qt/element/QtCodeArea.h +++ b/src/lib_gui/qt/element/QtCodeArea.h @@ -79,6 +79,7 @@ public: Id getLocationIdOfFirstActiveLocation(Id tokenId) const; Id getLocationIdOfFirstActiveScopeLocation(Id tokenId) const; + Id getLocationIdOfFirstHighlightedLocation() const; size_t getActiveLocationCount() const; @@ -87,6 +88,8 @@ public: void findScreenMatches(const std::wstring& query, std::vector>* screenMatches); void clearScreenMatches(); + void ensureLocationIdVisible(Id locationId, int parentWidth, bool animated); + protected: virtual void resizeEvent(QResizeEvent* event) Q_DECL_OVERRIDE; virtual void mouseReleaseEvent(QMouseEvent* event) Q_DECL_OVERRIDE; diff --git a/src/lib_gui/qt/element/QtCodeField.cpp b/src/lib_gui/qt/element/QtCodeField.cpp index 3cb70949..0581a64d 100644 --- a/src/lib_gui/qt/element/QtCodeField.cpp +++ b/src/lib_gui/qt/element/QtCodeField.cpp @@ -101,20 +101,16 @@ QSize QtCodeField::sizeHint() const int width = 0; QFontMetrics fm = fontMetrics(); - int maxTextSize = 0; for (QTextBlock block = document()->firstBlock(); block.isValid(); block = block.next()) { QRectF rect = blockBoundingGeometry(block); height += rect.height(); - { - int blockWidth = fm.boundingRect( - 0, 0, 1000000, 1000000, - Qt::AlignLeft | Qt::AlignTop | Qt::TextExpandTabs, block.text(), tabStopWidth()).width(); + int blockWidth = fm.boundingRect( + 0, 0, 1000000, 1000000, + Qt::AlignLeft | Qt::AlignTop | Qt::TextExpandTabs, block.text(), tabStopWidth()).width(); - width = std::max(blockWidth, width); - maxTextSize = block.text().size(); - } + width = std::max(blockWidth, width); } return QSize(width + 1, height + 5); diff --git a/src/lib_gui/qt/element/QtCodeFileList.cpp b/src/lib_gui/qt/element/QtCodeFileList.cpp index f450cf16..ffc6fff8 100644 --- a/src/lib_gui/qt/element/QtCodeFileList.cpp +++ b/src/lib_gui/qt/element/QtCodeFileList.cpp @@ -228,6 +228,9 @@ bool QtCodeFileList::requestScroll(const FilePath& filePath, uint lineNumber, Id } ensureWidgetVisibleAnimated(m_filesArea, snippet, lineRect, animated, target); + + snippet->ensureLocationIdVisible(locationId, animated); + return true; } diff --git a/src/lib_gui/qt/element/QtCodeFileSingle.cpp b/src/lib_gui/qt/element/QtCodeFileSingle.cpp index 8a2e1816..9cbd24ef 100644 --- a/src/lib_gui/qt/element/QtCodeFileSingle.cpp +++ b/src/lib_gui/qt/element/QtCodeFileSingle.cpp @@ -197,6 +197,8 @@ bool QtCodeFileSingle::requestScroll( double percentB = endLineNumber ? double(endLineNumber - 1) / m_area->getEndLineNumber() : 0.0f; ensurePercentVisibleAnimated(percentA, percentB, animated, target); + m_area->ensureLocationIdVisible(locationId, width(), animated); + m_scrollRequested = true; return true; diff --git a/src/lib_gui/qt/element/QtCodeSnippet.cpp b/src/lib_gui/qt/element/QtCodeSnippet.cpp index 7bb3f890..bdc2613c 100644 --- a/src/lib_gui/qt/element/QtCodeSnippet.cpp +++ b/src/lib_gui/qt/element/QtCodeSnippet.cpp @@ -142,6 +142,8 @@ int QtCodeSnippet::lineNumberDigits() const void QtCodeSnippet::updateCodeSnippet(const CodeSnippetParams& params) { m_codeArea->updateSourceLocations(params.locationFile); + + ensureLocationIdVisible(m_codeArea->getLocationIdOfFirstHighlightedLocation(), false); } void QtCodeSnippet::updateLineNumberAreaWidthForDigits(int digits) @@ -197,6 +199,11 @@ void QtCodeSnippet::findScreenMatches(const std::wstring& query, std::vectorfindScreenMatches(query, screenMatches); } +void QtCodeSnippet::ensureLocationIdVisible(Id locationId, bool animated) +{ + m_codeArea->ensureLocationIdVisible(locationId, width(), animated); +} + void QtCodeSnippet::clickedTitle() { if (m_titleId > 0) diff --git a/src/lib_gui/qt/element/QtCodeSnippet.h b/src/lib_gui/qt/element/QtCodeSnippet.h index a7c5bc46..cd66f7b0 100644 --- a/src/lib_gui/qt/element/QtCodeSnippet.h +++ b/src/lib_gui/qt/element/QtCodeSnippet.h @@ -54,6 +54,8 @@ public: void findScreenMatches(const std::wstring& query, std::vector>* screenMatches); + void ensureLocationIdVisible(Id locationId, bool animated); + private slots: void clickedTitle(); void clickedFooter();