ui: code view scrolls directly to active line

This change makes the code view first look for the rect of the first active line and then tries to scroll this line into
the middle of the view.
This commit is contained in:
Eberhard Graether
2015-11-13 10:39:30 +01:00
parent de4f2973bc
commit df7c5ea9b7
12 changed files with 72 additions and 68 deletions
+16
View File
@@ -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);
+2
View File
@@ -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;
+2 -2
View File
@@ -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)
{
+2 -2
View File
@@ -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();
+18 -50
View File
@@ -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<QtCodeFile> 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<TokenLocationFile> 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();
}
+4 -3
View File
@@ -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<TokenLocationFile> locationFile);
void updateFiles();
void ensureWidgetVisibleAnimated(QWidget *childWidget, int xmargin = 50, int ymargin = 50);
void ensureWidgetVisibleAnimated(QWidget *childWidget, QRectF rect);
std::shared_ptr<QFrame> m_frame;
std::vector<std::shared_ptr<QtCodeFile>> m_files;
+5
View File
@@ -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);
+2
View File
@@ -44,6 +44,8 @@ public:
void setIsActiveFile(bool isActiveFile);
QRectF getFirstActiveLineRect() const;
protected:
virtual void contextMenuEvent(QContextMenuEvent* event) Q_DECL_OVERRIDE;
+13 -5
View File
@@ -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<CodeSnippetParams>& snippets
m_showCodeSnippetsFunctor(snippets);
}
void QtCodeView::addCodeSnippets(const std::vector<CodeSnippetParams>& snippets)
void QtCodeView::addCodeSnippets(const std::vector<CodeSnippetParams>& 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<CodeSnippetParams>& snippe
setStyleSheet(); // so property "isLast" of QtCodeSnippet is computed correctly
}
void QtCodeView::doAddCodeSnippets(const std::vector<CodeSnippetParams>& snippets)
void QtCodeView::doAddCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert)
{
for (const CodeSnippetParams& params : snippets)
{
@@ -129,11 +130,17 @@ void QtCodeView::doAddCodeSnippets(const std::vector<CodeSnippetParams>& 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;
}
}
+5 -3
View File
@@ -30,7 +30,7 @@ public:
virtual void setErrorMessages(const std::vector<std::string>& errorMessages);
virtual void showCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
virtual void addCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
virtual void addCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert);
virtual void showCodeFile(const CodeSnippetParams& params);
virtual void showFirstActiveSnippet();
@@ -42,7 +42,7 @@ private:
void doRefreshView();
void doShowCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
void doAddCodeSnippets(const std::vector<CodeSnippetParams>& snippets);
void doAddCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert);
void doShowCodeFile(const CodeSnippetParams& params);
void doShowFirstActiveSnippet();
@@ -54,7 +54,7 @@ private:
QtThreadedFunctor<> m_refreshViewFunctor;
QtThreadedFunctor<const std::vector<CodeSnippetParams>&> m_showCodeSnippetsFunctor;
QtThreadedFunctor<const std::vector<CodeSnippetParams>&> m_addCodeSnippetsFunctor;
QtThreadedFunctor<const std::vector<CodeSnippetParams>&, bool> m_addCodeSnippetsFunctor;
QtThreadedFunctor<const CodeSnippetParams&> m_showCodeFileFunctor;
QtThreadedFunctor<> m_doShowFirstActiveSnippetFunctor;
QtThreadedFunctor<const std::vector<Id>&> m_focusTokenIdsFunctor;
@@ -64,6 +64,8 @@ private:
std::vector<Id> m_activeTokenIds;
std::vector<std::string> m_errorMessages;
bool m_isExpanding;
};
# endif // QT_CODE_VIEW_H
@@ -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()
+1 -1
View File
@@ -47,7 +47,7 @@ public:
virtual void setErrorMessages(const std::vector<std::string>& errorMessages) = 0;
virtual void showCodeSnippets(const std::vector<CodeSnippetParams>& snippets) = 0;
virtual void addCodeSnippets(const std::vector<CodeSnippetParams>& snippets) = 0;
virtual void addCodeSnippets(const std::vector<CodeSnippetParams>& snippets, bool insert) = 0;
virtual void showCodeFile(const CodeSnippetParams& params) = 0;
virtual void showFirstActiveSnippet() = 0;