diff --git a/src/lib/component/controller/GraphController.cpp b/src/lib/component/controller/GraphController.cpp index ef0499ab..c9c46d7b 100644 --- a/src/lib/component/controller/GraphController.cpp +++ b/src/lib/component/controller/GraphController.cpp @@ -36,7 +36,7 @@ void GraphController::handleMessage(MessageActivateAll* message) layoutNesting(); layoutGraph(); - buildGraph(message); + buildGraph(message, false); } void GraphController::handleMessage(MessageActivateTokens* message) @@ -47,7 +47,7 @@ void GraphController::handleMessage(MessageActivateTokens* message) { m_activeEdgeIds = message->tokenIds; setActiveAndVisibility(utility::concat(m_activeNodeIds, m_activeEdgeIds)); - buildGraph(message); + buildGraph(message, false); return; } else if (message->isAggregation) @@ -81,12 +81,12 @@ void GraphController::handleMessage(MessageActivateTokens* message) layoutNesting(); layoutGraph(true); - buildGraph(message); + buildGraph(message, true); } void GraphController::handleMessage(MessageFlushUpdates* message) { - buildGraph(message); + buildGraph(message, true); } void GraphController::handleMessage(MessageSearchFullText* message) @@ -133,7 +133,7 @@ void GraphController::handleMessage(MessageGraphNodeBundleSplit* message) layoutNesting(); layoutGraph(tokenIds.size() > 0); - buildGraph(message); + buildGraph(message, false); } void GraphController::handleMessage(MessageGraphNodeExpand* message) @@ -148,7 +148,7 @@ void GraphController::handleMessage(MessageGraphNodeExpand* message) layoutNesting(); layoutGraph(); - buildGraph(message); + buildGraph(message, false); } } @@ -161,7 +161,7 @@ void GraphController::handleMessage(MessageGraphNodeMove* message) if (message->isReplayed()) { - buildGraph(message); + buildGraph(message, false); } else { @@ -1148,11 +1148,15 @@ DummyNode* GraphController::getDummyGraphNodeById(Id tokenId) const return nullptr; } -void GraphController::buildGraph(MessageBase* message, bool animated) +void GraphController::buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition) { if (!message->isReplayed()) { - getView()->rebuildGraph(m_graph, m_dummyNodes, m_dummyEdges, animated); + GraphView::GraphParams params; + params.centerActiveNode = centerActiveNode; + params.animatedTransition = animatedTransition; + + getView()->rebuildGraph(m_graph, m_dummyNodes, m_dummyEdges, params); } } diff --git a/src/lib/component/controller/GraphController.h b/src/lib/component/controller/GraphController.h index 221ed1fd..37abab70 100644 --- a/src/lib/component/controller/GraphController.h +++ b/src/lib/component/controller/GraphController.h @@ -93,7 +93,7 @@ private: DummyNode* getDummyGraphNodeById(Id tokenId) const; - void buildGraph(MessageBase* message, bool animated = true); + void buildGraph(MessageBase* message, bool centerActiveNode, bool animatedTransition = true); void forEachDummyNodeRecursive(std::function func); void forEachDummyEdge(std::function func); diff --git a/src/lib/component/view/GraphView.h b/src/lib/component/view/GraphView.h index cb5ae475..791b2aa8 100644 --- a/src/lib/component/view/GraphView.h +++ b/src/lib/component/view/GraphView.h @@ -9,9 +9,16 @@ struct DummyEdge; struct DummyNode; class Graph; -class GraphView : public View +class GraphView + : public View { public: + struct GraphParams + { + bool animatedTransition; + bool centerActiveNode; + }; + GraphView(ViewLayout* viewLayout); virtual ~GraphView(); @@ -21,7 +28,7 @@ public: std::shared_ptr graph, const std::vector>& nodes, const std::vector>& edges, - bool animated) = 0; + const GraphParams params) = 0; virtual void clear() = 0; virtual void focusTokenIds(const std::vector& focusedTokenIds) = 0; diff --git a/src/lib_gui/qt/graphics/QtGraphicsView.cpp b/src/lib_gui/qt/graphics/QtGraphicsView.cpp index ced83cf1..4ab7ba52 100644 --- a/src/lib_gui/qt/graphics/QtGraphicsView.cpp +++ b/src/lib_gui/qt/graphics/QtGraphicsView.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include + QtGraphicsView::QtGraphicsView(QWidget* parent) : QGraphicsView(parent) , m_zoomFactor(1.0f) @@ -17,7 +20,7 @@ QtGraphicsView::QtGraphicsView(QWidget* parent) setTransformationAnchor(QGraphicsView::AnchorUnderMouse); m_timer = std::make_shared(this); - connect(m_timer.get(), SIGNAL(timeout()), this, SLOT(update())); + connect(m_timer.get(), SIGNAL(timeout()), this, SLOT(updateTimer())); m_timerStopper = std::make_shared(this); m_timerStopper->setSingleShot(true); @@ -35,6 +38,38 @@ void QtGraphicsView::setAppZoomFactor(float appZoomFactor) updateTransform(); } +void QtGraphicsView::ensureVisibleAnimated(const QRectF& rect, int xmargin, int ymargin) +{ + int xval = horizontalScrollBar()->value(); + int yval = verticalScrollBar()->value(); + + ensureVisible(rect, xmargin, ymargin); + + int xval2 = horizontalScrollBar()->value(); + int yval2 = verticalScrollBar()->value(); + + horizontalScrollBar()->setValue(xval); + verticalScrollBar()->setValue(yval); + + QParallelAnimationGroup* move = new QParallelAnimationGroup(); + + QPropertyAnimation* xanim = new QPropertyAnimation(horizontalScrollBar(), "value"); + xanim->setDuration(150); + xanim->setStartValue(xval); + xanim->setEndValue(xval2); + xanim->setEasingCurve(QEasingCurve::InOutQuad); + move->addAnimation(xanim); + + QPropertyAnimation* yanim = new QPropertyAnimation(verticalScrollBar(), "value"); + yanim->setDuration(150); + yanim->setStartValue(yval); + yanim->setEndValue(yval2); + yanim->setEasingCurve(QEasingCurve::InOutQuad); + move->addAnimation(yanim); + + move->start(); +} + void QtGraphicsView::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton && !itemAt(event->pos())) @@ -134,7 +169,7 @@ void QtGraphicsView::wheelEvent(QWheelEvent* event) QGraphicsView::wheelEvent(event); } -void QtGraphicsView::update() +void QtGraphicsView::updateTimer() { float ds = 30.0f; float dz = 50.0f; diff --git a/src/lib_gui/qt/graphics/QtGraphicsView.h b/src/lib_gui/qt/graphics/QtGraphicsView.h index 01b74e1a..63756e5b 100644 --- a/src/lib_gui/qt/graphics/QtGraphicsView.h +++ b/src/lib_gui/qt/graphics/QtGraphicsView.h @@ -20,6 +20,8 @@ public: float getZoomFactor() const; void setAppZoomFactor(float appZoomFactor); + void ensureVisibleAnimated(const QRectF& rect, int xmargin = 50, int ymargin = 50); + protected: void mousePressEvent(QMouseEvent *event); void mouseReleaseEvent(QMouseEvent *event); @@ -33,7 +35,7 @@ signals: void emptySpaceClicked(); private slots: - void update(); + void updateTimer(); void stopTimer(); private: diff --git a/src/lib_gui/qt/view/QtGraphView.cpp b/src/lib_gui/qt/view/QtGraphView.cpp index 3307f46d..7f1d0f95 100644 --- a/src/lib_gui/qt/view/QtGraphView.cpp +++ b/src/lib_gui/qt/view/QtGraphView.cpp @@ -84,9 +84,9 @@ void QtGraphView::rebuildGraph( std::shared_ptr graph, const std::vector>& nodes, const std::vector>& edges, - bool animated + const GraphParams params ){ - m_rebuildGraphFunctor(graph, nodes, edges, animated); + m_rebuildGraphFunctor(graph, nodes, edges, params); } void QtGraphView::clear() @@ -166,7 +166,7 @@ void QtGraphView::switchToNewGraphData() doResize(); // Manually hover the item below the mouse cursor. - QGraphicsView* view = getView(); + QtGraphicsView* view = getView(); QPointF point = view->mapToScene(view->mapFromGlobal(QCursor::pos())); QGraphicsItem* item = view->scene()->itemAt(point, QTransform()); if (item) @@ -178,6 +178,22 @@ void QtGraphView::switchToNewGraphData() } } + if (m_activeNode) + { + Vec2i pos = m_activeNode->getPosition(); + Vec2i size = m_activeNode->getSize(); + + QRectF rect(pos.x, pos.y, size.x, size.y); + + if (rect.height() > view->height() - 200) + { + rect.setHeight(view->height() - 200); + } + + view->ensureVisibleAnimated(rect, 100, 100); + m_activeNode.reset(); + } + // Repaint to make sure all artifacts are removed view->update(); } @@ -200,7 +216,7 @@ void QtGraphView::doRebuildGraph( std::shared_ptr graph, const std::vector>& nodes, const std::vector>& edges, - bool animated + const GraphParams params ){ if (m_transition && m_transition->currentTime() < m_transition->totalDuration()) { @@ -217,6 +233,7 @@ void QtGraphView::doRebuildGraph( } m_nodes.clear(); + m_activeNode.reset(); for (unsigned int i = 0; i < nodes.size(); i++) { std::shared_ptr node = createNodeRecursive(view, NULL, nodes[i].get(), activeNodeCount > 1); @@ -251,7 +268,7 @@ void QtGraphView::doRebuildGraph( m_graph = graph; } - if (animated) + if (params.animatedTransition) { createTransition(); } @@ -259,6 +276,11 @@ void QtGraphView::doRebuildGraph( { switchToNewGraphData(); } + + if (!params.centerActiveNode) + { + m_activeNode.reset(); + } } void QtGraphView::doClear() @@ -352,6 +374,11 @@ std::shared_ptr QtGraphView::createNodeRecursive( newNode->addComponent(std::make_shared(newNode)); } + if (node->active && !m_activeNode) + { + m_activeNode = newNode; + } + for (unsigned int i = 0; i < node->subNodes.size(); i++) { std::shared_ptr subNode = createNodeRecursive(view, newNode, node->subNodes[i].get(), multipleActive); @@ -544,13 +571,10 @@ void QtGraphView::createTransition() anim->setStartValue(view->sceneRect()); anim->setEndValue(getSceneRect(m_nodes)); - if (remainingNodes.size()) + anim->setDuration(300); + + if (!remainingNodes.size()) { - anim->setDuration(300); - } - else - { - anim->setDuration(300); connect(anim, SIGNAL(finished()), this, SLOT(centerScrollBars())); } diff --git a/src/lib_gui/qt/view/QtGraphView.h b/src/lib_gui/qt/view/QtGraphView.h index 447d062c..b56fe306 100644 --- a/src/lib_gui/qt/view/QtGraphView.h +++ b/src/lib_gui/qt/view/QtGraphView.h @@ -35,7 +35,7 @@ public: std::shared_ptr graph, const std::vector>& nodes, const std::vector>& edges, - bool animated); + const GraphParams params); virtual void clear(); virtual void focusTokenIds(const std::vector& focusedTokenIds); @@ -59,7 +59,7 @@ private: std::shared_ptr graph, const std::vector>& nodes, const std::vector>& edges, - bool animated); + const GraphParams params); void doClear(); void doResize(); void doRefreshView(); @@ -89,7 +89,7 @@ private: std::shared_ptr, const std::vector>&, const std::vector>&, - bool + const GraphParams > m_rebuildGraphFunctor; QtThreadedFunctor m_clearFunctor; QtThreadedFunctor m_resizeFunctor; @@ -106,6 +106,8 @@ private: std::list> m_nodes; std::list> m_oldNodes; + std::shared_ptr m_activeNode; + std::shared_ptr m_transition; QPointF m_sceneRectOffset; };