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:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -44,6 +44,8 @@ public:
|
||||
|
||||
void setIsActiveFile(bool isActiveFile);
|
||||
|
||||
QRectF getFirstActiveLineRect() const;
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent(QContextMenuEvent* event) Q_DECL_OVERRIDE;
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user