ui: scroll to code snippet containing clicked edge

This change scrolls animated to the snippet representing the clicked edge instead of showing only this code snippet.
This commit is contained in:
Eberhard Graether
2015-05-31 22:52:16 +02:00
parent 3e419bb41f
commit 20ce168712
12 changed files with 187 additions and 16 deletions
+19 -4
View File
@@ -148,6 +148,21 @@ void QtCodeArea::updateContent()
annotateText();
}
bool QtCodeArea::isActive() const
{
const std::vector<Id>& ids = m_fileWidget->getActiveTokenIds();
for (const Annotation& annotation: m_annotations)
{
if (std::find(ids.begin(), ids.end(), annotation.tokenId) != ids.end())
{
return true;
}
}
return false;
}
void QtCodeArea::resizeEvent(QResizeEvent *e)
{
QPlainTextEdit::resizeEvent(e);
@@ -167,7 +182,6 @@ void QtCodeArea::showEvent(QShowEvent* event)
void QtCodeArea::paintEvent(QPaintEvent* event)
{
QPainter painter(viewport());
// painter.fillRect(rect(), Qt::white);
QTextBlock block = firstVisibleBlock();
int top = blockBoundingGeometry(block).translated(contentOffset()).top();
@@ -177,7 +191,7 @@ void QtCodeArea::paintEvent(QPaintEvent* event)
for (const ScopeAnnotation& scope : m_scopeAnnotations)
{
if (scope.isFocused)
if (scope.isFocused || scope.startLine == scope.endLine)
{
qColor = QColor("#90E4EEF2");
}
@@ -410,7 +424,7 @@ void QtCodeArea::annotateText()
selection.cursor.setPosition(annotation.end, QTextCursor::KeepAnchor);
scopeAnnotation.endLine = selection.cursor.blockNumber();
if (annotation.isScope)
if (annotation.isScope || (isActive && ids.size() == 1))
{
if (isActive || isFocused)
{
@@ -422,7 +436,8 @@ void QtCodeArea::annotateText()
scopeAnnotations.push_back(scopeAnnotation);
}
}
else
if (!annotation.isScope || (isActive && ids.size() == 1))
{
extraSelections.append(selection);
}
+2
View File
@@ -58,6 +58,8 @@ public:
void updateContent();
bool isActive() const;
protected:
virtual void resizeEvent(QResizeEvent *event);
virtual void showEvent(QShowEvent* event);
+13
View File
@@ -143,6 +143,19 @@ void QtCodeFile::addCodeSnippet(
clickedSnippetButton();
}
QWidget* QtCodeFile::findFirstActiveSnippet() const
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
{
if (snippet->isActive())
{
return snippet.get();
}
}
return nullptr;
}
void QtCodeFile::updateContent()
{
for (std::shared_ptr<QtCodeSnippet> snippet : m_snippets)
+5 -1
View File
@@ -37,12 +37,16 @@ public:
std::shared_ptr<TokenLocationFile> locationFile
);
QWidget* findFirstActiveSnippet() const;
void updateContent();
public slots:
void clickedSnippetButton();
private slots:
void clickedTitle();
void clickedMinimizeButton();
void clickedSnippetButton();
void clickedMaximizeButton();
private:
+99 -4
View File
@@ -1,6 +1,8 @@
#include "qt/element/QtCodeFileList.h"
#include <QPropertyAnimation>
#include <QScrollBar>
#include <QVariant>
#include <QVBoxLayout>
#include "utility/file/FileSystem.h"
@@ -23,6 +25,8 @@ QtCodeFileList::QtCodeFileList(QWidget* parent)
setWidgetResizable(true);
setWidget(m_frame.get());
connect(this, SIGNAL(shouldScrollToSnippet(QWidget*)), this, SLOT(scrollToSnippet(QWidget*)), Qt::QueuedConnection);
}
QtCodeFileList::~QtCodeFileList()
@@ -83,7 +87,6 @@ const std::vector<Id>& QtCodeFileList::getActiveTokenIds() const
void QtCodeFileList::setActiveTokenIds(const std::vector<Id>& activeTokenIds)
{
m_activeTokenIds = activeTokenIds;
updateFiles();
}
const std::vector<std::string>& QtCodeFileList::getErrorMessages() const
@@ -94,14 +97,26 @@ const std::vector<std::string>& QtCodeFileList::getErrorMessages() const
void QtCodeFileList::setErrorMessages(const std::vector<std::string>& errorMessages)
{
m_errorMessages = errorMessages;
updateFiles();
}
void QtCodeFileList::updateFiles()
void QtCodeFileList::scrollToFirstActiveSnippet()
{
updateFiles();
QWidget* widget = nullptr;
for (std::shared_ptr<QtCodeFile> file: m_files)
{
file->updateContent();
widget = file->findFirstActiveSnippet();
if (widget)
{
if (!widget->isVisible())
{
file->clickedSnippetButton();
}
emit shouldScrollToSnippet(widget);
return;
}
}
}
@@ -116,3 +131,83 @@ void QtCodeFileList::defocusToken()
m_focusedTokenId = 0;
updateFiles();
}
void QtCodeFileList::scrollToSnippet(QWidget* widget)
{
this->ensureWidgetVisibleAnimated(widget);
}
void QtCodeFileList::updateFiles()
{
for (std::shared_ptr<QtCodeFile> file: m_files)
{
file->updateContent();
}
}
void QtCodeFileList::ensureWidgetVisibleAnimated(QWidget *childWidget, int xmargin, int ymargin)
{
if (!widget()->isAncestorOf(childWidget))
{
return;
}
const QRect microFocus = childWidget->inputMethodQuery(Qt::ImCursorRectangle).toRect();
const QRect defaultMicroFocus = childWidget->QWidget::inputMethodQuery(Qt::ImCursorRectangle).toRect();
QRect focusRect = (microFocus != defaultMicroFocus)
? QRect(childWidget->mapTo(widget(), microFocus.topLeft()), microFocus.size())
: QRect(childWidget->mapTo(widget(), QPoint(0, 0)), childWidget->size());
const QRect visibleRect(-widget()->pos(), viewport()->size());
if (visibleRect.contains(focusRect))
{
return;
}
focusRect.adjust(-xmargin, -ymargin, xmargin, ymargin);
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)
{
QPropertyAnimation* anim = new QPropertyAnimation(scrollBar, "value");
anim->setDuration(std::abs(scrollBar->value() - value));
anim->setStartValue(scrollBar->value());
anim->setEndValue(value);
anim->setEasingCurve(QEasingCurve::OutQuad);
anim->start();
}
}
+10
View File
@@ -17,6 +17,9 @@ class QtCodeFileList
{
Q_OBJECT
signals:
void shouldScrollToSnippet(QWidget* widget);
public:
QtCodeFileList(QWidget* parent = 0);
virtual ~QtCodeFileList();
@@ -40,12 +43,19 @@ public:
const std::vector<std::string>& getErrorMessages() const;
void setErrorMessages(const std::vector<std::string>& errorMessages);
void scrollToFirstActiveSnippet();
void focusToken(Id tokenId);
void defocusToken();
private slots:
void scrollToSnippet(QWidget* widget);
private:
void updateFiles();
void ensureWidgetVisibleAnimated(QWidget *childWidget, int xmargin = 50, int ymargin = 50);
std::shared_ptr<QFrame> m_frame;
std::vector<std::shared_ptr<QtCodeFile>> m_files;
+5
View File
@@ -71,6 +71,11 @@ void QtCodeSnippet::updateContent()
updateDots();
}
bool QtCodeSnippet::isActive() const
{
return m_codeArea->isActive();
}
void QtCodeSnippet::updateDots()
{
if (!m_dots)
+2
View File
@@ -34,6 +34,8 @@ public:
void updateLineNumberAreaWidthForDigits(int digits);
void updateContent();
bool isActive() const;
private:
void updateDots();
+19 -7
View File
@@ -11,6 +11,7 @@ QtCodeView::QtCodeView(ViewLayout* viewLayout)
, m_refreshViewFunctor(std::bind(&QtCodeView::doRefreshView, this))
, m_showCodeSnippetsFunctor(std::bind(&QtCodeView::doShowCodeSnippets, this, std::placeholders::_1))
, m_showCodeFileFunctor(std::bind(&QtCodeView::doShowCodeFile, this, std::placeholders::_1))
, m_doScrollToFirstActiveSnippetFunctor(std::bind(&QtCodeView::doScrollToFirstActiveSnippet, this))
, m_focusTokenFunctor(std::bind(&QtCodeView::doFocusToken, this, std::placeholders::_1))
, m_defocusTokenFunctor(std::bind(&QtCodeView::doDefocusToken, this))
{
@@ -56,6 +57,21 @@ void QtCodeView::showCodeFile(const CodeSnippetParams& params)
m_showCodeFileFunctor(params);
}
void QtCodeView::scrollToFirstActiveSnippet()
{
m_doScrollToFirstActiveSnippetFunctor();
}
void QtCodeView::focusToken(const Id tokenId)
{
m_focusTokenFunctor(tokenId);
}
void QtCodeView::defocusToken()
{
m_defocusTokenFunctor();
}
void QtCodeView::doRefreshView()
{
setStyleSheet(m_widget);
@@ -79,14 +95,10 @@ void QtCodeView::doShowCodeFile(const CodeSnippetParams& params)
m_widget->addCodeSnippet(1, params.title, params.code, params.locationFile);
}
void QtCodeView::focusToken(const Id tokenId)
void QtCodeView::doScrollToFirstActiveSnippet()
{
m_focusTokenFunctor(tokenId);
}
void QtCodeView::defocusToken()
{
m_defocusTokenFunctor();
m_widget->setActiveTokenIds(m_activeTokenIds);
m_widget->scrollToFirstActiveSnippet();
}
void QtCodeView::doFocusToken(const Id tokenId)
+5
View File
@@ -32,6 +32,8 @@ public:
virtual void showCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
virtual void showCodeFile(const CodeSnippetParams& params);
virtual void scrollToFirstActiveSnippet();
virtual void focusToken(const Id tokenId);
virtual void defocusToken();
@@ -41,6 +43,8 @@ private:
void doShowCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
void doShowCodeFile(const CodeSnippetParams& params);
void doScrollToFirstActiveSnippet();
void doFocusToken(const Id tokenId);
void doDefocusToken();
@@ -49,6 +53,7 @@ private:
QtThreadedFunctor<> m_refreshViewFunctor;
QtThreadedFunctor<const std::vector<CodeSnippetParams>&> m_showCodeSnippetsFunctor;
QtThreadedFunctor<const CodeSnippetParams&> m_showCodeFileFunctor;
QtThreadedFunctor<> m_doScrollToFirstActiveSnippetFunctor;
QtThreadedFunctor<const Id&> m_focusTokenFunctor;
QtThreadedFunctor<> m_defocusTokenFunctor;
@@ -52,6 +52,12 @@ void CodeController::handleMessage(MessageActivateTokens* message)
view->setActiveTokenIds(activeTokenIds);
view->setErrorMessages(std::vector<std::string>());
if (message->isEdge)
{
view->scrollToFirstActiveSnippet();
return;
}
TokenLocationCollection collection = m_storageAccess->getTokenLocationsForTokenIds(activeTokenIds);
view->showCodeSnippets(getSnippetsForActiveTokenLocations(collection, declarationId));
+2
View File
@@ -43,6 +43,8 @@ public:
virtual void showCodeSnippets(const std::vector<CodeSnippetParams>& snippets) = 0;
virtual void showCodeFile(const CodeSnippetParams& params) = 0;
virtual void scrollToFirstActiveSnippet() = 0;
virtual void focusToken(const Id tokenId) = 0;
virtual void defocusToken() = 0;