From 19f2d3a7a8ed1be36835f5e363796c915dc1207e Mon Sep 17 00:00:00 2001 From: Knud Dollereder Date: Wed, 7 Oct 2020 13:05:50 +0200 Subject: [PATCH] Enable touch-pad navigation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For the curve-editor, transition-editor and timeline Renamed ruler-scaling-factor to zoom in order to not confuse it with ruler-scale-factor Change-Id: I099e8e9a1e6092c9abb0a1a935fb8510aa90d5e4 Reviewed-by: Henning Gründl Reviewed-by: Thomas Hartmann --- src/plugins/qmldesigner/CMakeLists.txt | 1 + .../componentcore/componentcore.pri | 2 + .../components/componentcore/navigation2d.cpp | 91 +++++++++++++++++++ .../components/componentcore/navigation2d.h | 67 ++++++++++++++ .../curveeditor/detail/graphicsview.cpp | 8 ++ .../curveeditor/detail/handleitem.cpp | 5 +- .../timelineeditor/timelinegraphicslayout.cpp | 11 ++- .../timelineeditor/timelinegraphicslayout.h | 6 +- .../timelineeditor/timelinegraphicsscene.cpp | 32 ++++--- .../timelineeditor/timelinegraphicsscene.h | 7 +- .../timelineeditor/timelinesectionitem.cpp | 12 +-- .../timelineeditor/timelinesectionitem.h | 6 +- .../timelineeditor/timelinewidget.cpp | 20 +++- .../timelineeditor/timelinewidget.h | 4 +- .../transitioneditorgraphicslayout.cpp | 11 ++- .../transitioneditorgraphicslayout.h | 6 +- .../transitioneditorgraphicsscene.cpp | 46 ++++++++-- .../transitioneditorgraphicsscene.h | 4 +- .../transitioneditorwidget.cpp | 18 +++- .../transitioneditor/transitioneditorwidget.h | 4 +- src/plugins/qmldesigner/qmldesignerplugin.qbs | 2 + 21 files changed, 311 insertions(+), 52 deletions(-) create mode 100644 src/plugins/qmldesigner/components/componentcore/navigation2d.cpp create mode 100644 src/plugins/qmldesigner/components/componentcore/navigation2d.h diff --git a/src/plugins/qmldesigner/CMakeLists.txt b/src/plugins/qmldesigner/CMakeLists.txt index 11be30c80e1..291948a7e7d 100644 --- a/src/plugins/qmldesigner/CMakeLists.txt +++ b/src/plugins/qmldesigner/CMakeLists.txt @@ -208,6 +208,7 @@ extend_qtc_plugin(QmlDesigner modelnodecontextmenu.cpp modelnodecontextmenu.h modelnodecontextmenu_helper.cpp modelnodecontextmenu_helper.h modelnodeoperations.cpp modelnodeoperations.h + navigation2d.cpp navigation2d.h qmldesignericonprovider.cpp qmldesignericonprovider.h selectioncontext.cpp selectioncontext.h theme.cpp theme.h diff --git a/src/plugins/qmldesigner/components/componentcore/componentcore.pri b/src/plugins/qmldesigner/components/componentcore/componentcore.pri index 14337508ec9..decf24a5a83 100644 --- a/src/plugins/qmldesigner/components/componentcore/componentcore.pri +++ b/src/plugins/qmldesigner/components/componentcore/componentcore.pri @@ -14,6 +14,7 @@ SOURCES += modelnodecontextmenu_helper.cpp SOURCES += selectioncontext.cpp SOURCES += designeractionmanager.cpp SOURCES += modelnodeoperations.cpp +SOURCES += navigation2d.cpp SOURCES += crumblebar.cpp SOURCES += qmldesignericonprovider.cpp SOURCES += zoomaction.cpp @@ -33,6 +34,7 @@ HEADERS += selectioncontext.h HEADERS += componentcore_constants.h HEADERS += designeractionmanager.h HEADERS += modelnodeoperations.h +HEADERS += navigation2d.h HEADERS += actioninterface.h HEADERS += crumblebar.h HEADERS += qmldesignericonprovider.h diff --git a/src/plugins/qmldesigner/components/componentcore/navigation2d.cpp b/src/plugins/qmldesigner/components/componentcore/navigation2d.cpp new file mode 100644 index 00000000000..94d6b5ad38f --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/navigation2d.cpp @@ -0,0 +1,91 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#include "navigation2d.h" + +#include +#include + +namespace QmlDesigner { + +Navigation2dScrollBar::Navigation2dScrollBar(QWidget *parent) + : QScrollBar(parent) +{} + +bool Navigation2dScrollBar::postEvent(QEvent *event) +{ + if (event->type() == QEvent::Wheel) { + wheelEvent(static_cast(event)); + return true; + } + return false; +} + +void Navigation2dScrollBar::wheelEvent(QWheelEvent *event) +{ + if (!event->angleDelta().isNull()) + QScrollBar::wheelEvent(event); +} + + +Navigation2dFilter::Navigation2dFilter(QWidget *parent, Navigation2dScrollBar *scrollbar) + : QObject(parent) + , m_scrollbar(scrollbar) +{ + if (parent) + parent->grabGesture(Qt::PinchGesture); +} + +bool Navigation2dFilter::eventFilter(QObject *, QEvent *event) +{ + if (event->type() == QEvent::Gesture) + return gestureEvent(static_cast(event)); + else if (event->type() == QEvent::Wheel && m_scrollbar) + return wheelEvent(static_cast(event)); + + return QObject::event(event); +} + +bool Navigation2dFilter::gestureEvent(QGestureEvent *event) +{ + if (QPinchGesture *pinch = static_cast(event->gesture(Qt::PinchGesture))) { + QPinchGesture::ChangeFlags changeFlags = pinch->changeFlags(); + if (changeFlags & QPinchGesture::ScaleFactorChanged) { + emit zoomChanged(-(1.0 - pinch->scaleFactor()), pinch->startCenterPoint()); + event->accept(); + return true; + } + } + return false; +} + +bool Navigation2dFilter::wheelEvent(QWheelEvent *event) +{ + if (m_scrollbar->postEvent(event)) + event->ignore(); + + return false; +} + +} // End namespace QmlDesigner. diff --git a/src/plugins/qmldesigner/components/componentcore/navigation2d.h b/src/plugins/qmldesigner/components/componentcore/navigation2d.h new file mode 100644 index 00000000000..434b59055ca --- /dev/null +++ b/src/plugins/qmldesigner/components/componentcore/navigation2d.h @@ -0,0 +1,67 @@ +/**************************************************************************** +** +** Copyright (C) 2020 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of Qt Creator. +** +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 as published by the Free Software +** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +****************************************************************************/ +#pragma once + +#include + +QT_FORWARD_DECLARE_CLASS(QGestureEvent) +QT_FORWARD_DECLARE_CLASS(QWheelEvent) + +namespace QmlDesigner { + +class Navigation2dScrollBar : public QScrollBar +{ + Q_OBJECT + +public: + Navigation2dScrollBar(QWidget *parent = nullptr); + + bool postEvent(QEvent *event); + +protected: + void wheelEvent(QWheelEvent *event) override; +}; + + +class Navigation2dFilter : public QObject +{ + Q_OBJECT + +signals: + void zoomChanged(double scale, const QPointF &pos); + +public: + Navigation2dFilter(QWidget *parent = nullptr, Navigation2dScrollBar *scrollbar = nullptr); + +protected: + bool eventFilter(QObject *obj, QEvent *event) override; + +private: + bool gestureEvent(QGestureEvent *event); + bool wheelEvent(QWheelEvent *event); + Navigation2dScrollBar *m_scrollbar = nullptr; +}; + +} // namespace QmlDesigner diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp index 36bae9be0c1..9fec8b2fc54 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/graphicsview.cpp @@ -27,6 +27,7 @@ #include "axis.h" #include "curveeditormodel.h" #include "curveitem.h" +#include "navigation2d.h" #include "treeitem.h" #include "utils.h" @@ -79,6 +80,13 @@ GraphicsView::GraphicsView(CurveEditorModel *model, QWidget *parent) applyZoom(m_zoomX, m_zoomY); update(); + + QmlDesigner::Navigation2dFilter *filter = new QmlDesigner::Navigation2dFilter(this); + auto zoomChanged = &QmlDesigner::Navigation2dFilter::zoomChanged; + connect(filter, zoomChanged, [this](double scale, const QPointF &pos) { + applyZoom(m_zoomX + scale, m_zoomY, mapToGlobal(pos.toPoint())); + }); + installEventFilter(filter); } GraphicsView::~GraphicsView() diff --git a/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.cpp b/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.cpp index 891f6896eae..0fdb00ff1b0 100644 --- a/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.cpp +++ b/src/plugins/qmldesigner/components/curveeditor/detail/handleitem.cpp @@ -41,8 +41,11 @@ struct HandleGeometry handle = QRectF(topLeft, -topLeft); toKeyframe = QLineF(QPointF(0.0, 0.0), -pos); angle = -toKeyframe.angle() + 45.0; + bbox = handle.united(QRectF(-pos, QSizeF(1.0,1.0))); } + QRectF bbox; + QRectF handle; QLineF toKeyframe; @@ -97,7 +100,7 @@ HandleItem::Slot HandleItem::slot() const QRectF HandleItem::boundingRect() const { HandleGeometry geom(pos(), m_style); - return geom.handle; + return geom.bbox; } bool HandleItem::contains(const QPointF &point) const diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.cpp index a0f0eedf292..007e8ae571a 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.cpp @@ -63,6 +63,11 @@ TimelineGraphicsLayout::TimelineGraphicsLayout(TimelineGraphicsScene *scene, Tim TimelineGraphicsLayout::~TimelineGraphicsLayout() = default; +int TimelineGraphicsLayout::zoom() const +{ + return m_rulerItem->zoom(); +} + double TimelineGraphicsLayout::rulerWidth() const { return m_rulerItem->preferredWidth(); @@ -133,12 +138,12 @@ void TimelineGraphicsLayout::setTimeline(const QmlTimeline &timeline) if (auto *scene = timelineScene()) if (auto *view = scene->timelineView()) if (!timeline.isValid() && view->isAttached()) - emit scaleFactorChanged(0); + emit zoomChanged(0); } -void TimelineGraphicsLayout::setRulerScaleFactor(int factor) +void TimelineGraphicsLayout::setZoom(int factor) { - m_rulerItem->setRulerScaleFactor(factor); + m_rulerItem->setZoom(factor); } void TimelineGraphicsLayout::invalidate() diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.h b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.h index f4d2ae58364..ce2423dfe97 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicslayout.h @@ -44,7 +44,7 @@ class TimelineGraphicsLayout : public TimelineItem signals: void rulerClicked(const QPointF &pos); - void scaleFactorChanged(int factor); + void zoomChanged(int factor); public: TimelineGraphicsLayout(TimelineGraphicsScene *scene, TimelineItem *parent = nullptr); @@ -52,6 +52,8 @@ public: ~TimelineGraphicsLayout() override; public: + int zoom() const; + double rulerWidth() const; double rulerScaling() const; @@ -66,7 +68,7 @@ public: void setTimeline(const QmlTimeline &timeline); - void setRulerScaleFactor(int factor); + void setZoom(int factor); void invalidate(); diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp index 0f87032519c..5c2621300fb 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.cpp @@ -123,9 +123,9 @@ TimelineGraphicsScene::TimelineGraphicsScene(TimelineWidget *parent) auto changeScale = [this](int factor) { timelineWidget()->changeScaleFactor(factor); - setRulerScaling(qreal(factor)); + setZoom(factor); }; - connect(m_layout, &TimelineGraphicsLayout::scaleFactorChanged, changeScale); + connect(m_layout, &TimelineGraphicsLayout::zoomChanged, changeScale); } TimelineGraphicsScene::~TimelineGraphicsScene() @@ -144,7 +144,7 @@ void TimelineGraphicsScene::onShow() setCurrentFrame(cf); } - emit m_layout->scaleFactorChanged(0); + emit m_layout->zoomChanged(0); } } @@ -271,6 +271,11 @@ void TimelineGraphicsScene::setEndFrame(int frame) timeline.modelNode().variantProperty("endFrame").setValue(frame); } +int TimelineGraphicsScene::zoom() const +{ + return m_layout->zoom(); +} + qreal TimelineGraphicsScene::rulerScaling() const { return m_layout->rulerScaling(); @@ -332,15 +337,20 @@ QVector TimelineGraphicsScene::keyframePositions(const QmlTimelineKeyfram return positions; } -void TimelineGraphicsScene::setRulerScaling(int scaleFactor) +void TimelineGraphicsScene::setZoom(int scaleFactor) +{ + setZoom(scaleFactor, currentFramePosition()); +} + +void TimelineGraphicsScene::setZoom(int scaleFactor, double pivot) { const qreal oldOffset = scrollOffset(); const qreal oldScaling = m_layout->rulerScaling(); - const qreal oldPosition = mapToScene(currentFramePosition()); - m_layout->setRulerScaleFactor(scaleFactor); + const qreal oldPosition = mapToScene(pivot); + m_layout->setZoom(scaleFactor); const qreal newScaling = m_layout->rulerScaling(); - const qreal newPosition = mapToScene(currentFramePosition()); + const qreal newPosition = mapToScene(pivot); const qreal newOffset = oldOffset + (newPosition - oldPosition); @@ -514,7 +524,7 @@ QRectF AbstractScrollGraphicsScene::selectionBounds() const } void AbstractScrollGraphicsScene::selectKeyframes(const SelectionMode &mode, - const QList &items) + const QList &items) { if (mode == SelectionMode::Remove || mode == SelectionMode::Toggle) { for (auto *item : items) { @@ -743,7 +753,7 @@ void TimelineGraphicsScene::deleteKeyframeGroup(const ModelNode &group) if (!QmlTimelineKeyframeGroup::isValidQmlTimelineKeyframeGroup(group)) return; - timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeGroupDeletion", [group](){ + timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeGroupDeletion", [group]() { ModelNode nonConst = group; nonConst.destroy(); }); @@ -751,7 +761,7 @@ void TimelineGraphicsScene::deleteKeyframeGroup(const ModelNode &group) void TimelineGraphicsScene::deleteKeyframes(const QList &frames) { - timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeDeletion", [frames](){ + timelineView()->executeInTransaction("TimelineGraphicsScene::handleKeyframeDeletion", [frames]() { for (auto keyframe : frames) { if (keyframe.isValid()) { ModelNode frame = keyframe; @@ -776,7 +786,7 @@ AbstractView *TimelineGraphicsScene::abstractView() const int AbstractScrollGraphicsScene::getScrollOffset(QGraphicsScene *scene) { - auto scrollScene = qobject_cast(scene); + auto scrollScene = qobject_cast(scene); if (scrollScene) return scrollScene->scrollOffset(); return 0; diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h index 8ef1c13092e..fc4da39f322 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinegraphicsscene.h @@ -58,7 +58,6 @@ class AbstractScrollGraphicsScene : public QGraphicsScene public: AbstractScrollGraphicsScene(QWidget *parent); - ; int scrollOffset() const; void setScrollOffset(int offset); @@ -74,6 +73,7 @@ public: bool isKeyframeSelected(TimelineKeyframeItem *keyframe) const; bool multipleKeyframesSelected() const; + virtual int zoom() const = 0; virtual qreal rulerScaling() const = 0; virtual int rulerWidth() const = 0; virtual qreal rulerDuration() const = 0; @@ -134,6 +134,7 @@ public: TimelineWidget *timelineWidget() const; TimelineToolBar *toolBar() const; + int zoom() const override; qreal rulerScaling() const override; int rulerWidth() const override; qreal rulerDuration() const override; @@ -152,7 +153,8 @@ public: qreal snap(qreal frame, bool snapToPlayhead = true) override; - void setRulerScaling(int scaling); + void setZoom(int scaling); + void setZoom(int scaling, double pivot); void commitCurrentFrame(qreal frame); @@ -204,7 +206,6 @@ private: QList itemsAt(const QPointF &pos); private: - TimelineWidget *m_parent = nullptr; TimelineGraphicsLayout *m_layout = nullptr; diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp index 4580240c5fb..1cff8012353 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.cpp @@ -569,9 +569,9 @@ void TimelineRulerSectionItem::invalidateRulerSize(const qreal length) m_end = length; } -void TimelineRulerSectionItem::setRulerScaleFactor(int scaling) +void TimelineRulerSectionItem::setZoom(int zoom) { - qreal blend = qreal(scaling) / 100.0; + qreal blend = qreal(zoom) / 100.0; qreal width = size().width() - qreal(TimelineConstants::sectionWidth); qreal duration = rulerDuration(); @@ -592,7 +592,7 @@ void TimelineRulerSectionItem::setRulerScaleFactor(int scaling) update(); } -int TimelineRulerSectionItem::getRulerScaleFactor() const +int TimelineRulerSectionItem::zoom() const { qreal width = size().width() - qreal(TimelineConstants::sectionWidth); qreal duration = rulerDuration(); @@ -609,7 +609,7 @@ int TimelineRulerSectionItem::getRulerScaleFactor() const qreal rcount = width / m_scaling; qreal rblend = TimelineUtils::reverseLerp(rcount, minCount, maxCount); - int rfactor = std::round(rblend * 100); + int rfactor = static_cast(std::round(rblend * 100)); return TimelineUtils::clamp(rfactor, 0, 100); } @@ -786,7 +786,7 @@ void TimelineRulerSectionItem::resizeEvent(QGraphicsSceneResizeEvent *event) { QGraphicsWidget::resizeEvent(event); - auto factor = getRulerScaleFactor(); + auto factor = zoom(); if (factor < 0) { if (event->oldSize().width() < event->newSize().width()) @@ -795,7 +795,7 @@ void TimelineRulerSectionItem::resizeEvent(QGraphicsSceneResizeEvent *event) factor = 100; } - emit scaleFactorChanged(factor); + emit zoomChanged(factor); } void TimelineRulerSectionItem::setSizeHints(int width) diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h index a31930b709b..956ef31ef78 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinesectionitem.h @@ -149,7 +149,7 @@ class TimelineRulerSectionItem : public TimelineItem signals: void rulerClicked(const QPointF &pos); - void scaleFactorChanged(int scale); + void zoomChanged(int zoom); public: static TimelineRulerSectionItem *create(QGraphicsScene *parentScene, TimelineItem *parent); @@ -157,9 +157,9 @@ public: void invalidateRulerSize(const QmlTimeline &timeline); void invalidateRulerSize(const qreal length); - void setRulerScaleFactor(int scaling); + void setZoom(int zoom); - int getRulerScaleFactor() const; + int zoom() const; qreal getFrameTick() const; qreal rulerScaling() const; diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp index e740fb924ec..6c7c15451de 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.cpp @@ -34,6 +34,7 @@ #include "timelinepropertyitem.h" #include "timelinetoolbar.h" #include "timelineview.h" +#include "navigation2d.h" #include #include @@ -60,6 +61,8 @@ #include #include +#include + namespace QmlDesigner { class Eventfilter : public QObject @@ -114,7 +117,7 @@ TimelineWidget::TimelineWidget(TimelineView *view) , m_toolbar(new TimelineToolBar(this)) , m_rulerView(new QGraphicsView(this)) , m_graphicsView(new QGraphicsView(this)) - , m_scrollbar(new QScrollBar(this)) + , m_scrollbar(new Navigation2dScrollBar(this)) , m_statusBar(new QLabel(this)) , m_timelineView(view) , m_graphicsScene(new TimelineGraphicsScene(this)) @@ -153,6 +156,7 @@ TimelineWidget::TimelineWidget(TimelineView *view) m_graphicsView->setFrameShape(QFrame::NoFrame); m_graphicsView->setFrameShadow(QFrame::Plain); m_graphicsView->setLineWidth(0); + m_graphicsView->setVerticalScrollBar(new Navigation2dScrollBar); m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -247,6 +251,14 @@ TimelineWidget::TimelineWidget(TimelineView *view) connect(m_addButton, &QPushButton::clicked, this, [this]() { m_timelineView->addNewTimelineDialog(); }); + + Navigation2dFilter *filter = new Navigation2dFilter(this, m_scrollbar); + connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF& pos) { + int s = static_cast(std::round(scale*100.)); + double ps = m_graphicsScene->mapFromScene(pos.x()); + m_graphicsScene->setZoom(std::clamp(m_graphicsScene->zoom() + s, 0, 100), ps); + }); + installEventFilter(filter); } void TimelineWidget::connectToolbar() @@ -258,8 +270,8 @@ void TimelineWidget::connectToolbar() connect(graphicsScene(), &TimelineGraphicsScene::scroll, this, &TimelineWidget::scroll); - auto setRulerScaling = [this](int val) { m_graphicsScene->setRulerScaling(val); }; - connect(m_toolbar, &TimelineToolBar::scaleFactorChanged, setRulerScaling); + auto setZoomFactor = [this](int val) { m_graphicsScene->setZoom(val); }; + connect(m_toolbar, &TimelineToolBar::scaleFactorChanged, setZoomFactor); auto setToFirstFrame = [this]() { graphicsScene()->setCurrentFrame(graphicsScene()->startFrame()); @@ -428,7 +440,7 @@ void TimelineWidget::init() // setScaleFactor uses QSignalBlocker. m_toolbar->setScaleFactor(0); - m_graphicsScene->setRulerScaling(0); + m_graphicsScene->setZoom(0); } void TimelineWidget::reset() diff --git a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h index b546452e560..b1e24caf937 100644 --- a/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h +++ b/src/plugins/qmldesigner/components/timelineeditor/timelinewidget.h @@ -36,7 +36,6 @@ QT_FORWARD_DECLARE_CLASS(QComboBox) QT_FORWARD_DECLARE_CLASS(QGraphicsView) QT_FORWARD_DECLARE_CLASS(QLabel) QT_FORWARD_DECLARE_CLASS(QResizeEvent) -QT_FORWARD_DECLARE_CLASS(QScrollBar) QT_FORWARD_DECLARE_CLASS(QShowEvent) QT_FORWARD_DECLARE_CLASS(QString) QT_FORWARD_DECLARE_CLASS(QPushButton) @@ -47,6 +46,7 @@ class TimelineToolBar; class TimelineView; class TimelineGraphicsScene; class QmlTimeline; +class Navigation2dScrollBar; class TimelineWidget : public QWidget { @@ -94,7 +94,7 @@ private: QGraphicsView *m_graphicsView = nullptr; - QScrollBar *m_scrollbar = nullptr; + Navigation2dScrollBar *m_scrollbar = nullptr; QLabel *m_statusBar = nullptr; diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.cpp index 02e1258dfd5..5abff4d6116 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.cpp @@ -65,6 +65,11 @@ TransitionEditorGraphicsLayout::TransitionEditorGraphicsLayout(QGraphicsScene *s TransitionEditorGraphicsLayout::~TransitionEditorGraphicsLayout() = default; +int TransitionEditorGraphicsLayout::zoom() const +{ + return m_rulerItem->zoom(); +} + double TransitionEditorGraphicsLayout::rulerWidth() const { return m_rulerItem->preferredWidth(); @@ -133,7 +138,7 @@ void TransitionEditorGraphicsLayout::setTransition(const ModelNode &transition) if (auto *scene = timelineScene()) if (auto *view = scene->timelineView()) if (!transition.isValid() && view->isAttached()) - emit scaleFactorChanged(0); + emit zoomChanged(0); } void TransitionEditorGraphicsLayout::setDuration(qreal duration) @@ -141,9 +146,9 @@ void TransitionEditorGraphicsLayout::setDuration(qreal duration) m_rulerItem->invalidateRulerSize(duration); } -void TransitionEditorGraphicsLayout::setRulerScaleFactor(int factor) +void TransitionEditorGraphicsLayout::setZoom(int factor) { - m_rulerItem->setRulerScaleFactor(factor); + m_rulerItem->setZoom(factor); } void TransitionEditorGraphicsLayout::invalidate() diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.h b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.h index 9362abffdfc..67495db20d8 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.h +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicslayout.h @@ -44,7 +44,7 @@ class TransitionEditorGraphicsLayout : public TimelineItem signals: void rulerClicked(const QPointF &pos); - void scaleFactorChanged(int factor); + void zoomChanged(int factor); public: TransitionEditorGraphicsLayout(QGraphicsScene *scene, TimelineItem *parent = nullptr); @@ -52,6 +52,8 @@ public: ~TransitionEditorGraphicsLayout() override; public: + int zoom() const; + double rulerWidth() const; double rulerScaling() const; @@ -66,7 +68,7 @@ public: void setDuration(qreal duration); - void setRulerScaleFactor(int factor); + void setZoom(int factor); void invalidate(); diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp index 3b14a9986cd..c080a49314e 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.cpp @@ -104,9 +104,9 @@ TransitionEditorGraphicsScene::TransitionEditorGraphicsScene(TransitionEditorWid auto changeScale = [this](int factor) { transitionEditorWidget()->changeScaleFactor(factor); - setRulerScaling(qreal(factor)); + setZoom(factor); }; - connect(m_layout, &TransitionEditorGraphicsLayout::scaleFactorChanged, changeScale); + connect(m_layout, &TransitionEditorGraphicsLayout::zoomChanged, changeScale); } TransitionEditorGraphicsScene::~TransitionEditorGraphicsScene() @@ -125,7 +125,7 @@ void TransitionEditorGraphicsScene::invalidateScrollbar() void TransitionEditorGraphicsScene::onShow() { - emit m_layout->scaleFactorChanged(0); + emit m_layout->zoomChanged(0); } void TransitionEditorGraphicsScene::setTransition(const ModelNode &transition) @@ -157,7 +157,12 @@ void TransitionEditorGraphicsScene::setDuration(int duration) m_transition.setAuxiliaryData("transitionDuration", duration); m_layout->setDuration(duration); qreal scaling = m_layout->rulerScaling(); - setRulerScaling(scaling); + setZoom(scaling); +} + +int TransitionEditorGraphicsScene::zoom() const +{ + return m_layout->zoom(); } qreal TransitionEditorGraphicsScene::rulerScaling() const @@ -199,9 +204,9 @@ qreal TransitionEditorGraphicsScene::mapFromScene(qreal x) const return xPosOffset / rulerScaling() + startFrame(); } -void TransitionEditorGraphicsScene::setRulerScaling(int scaleFactor) +void TransitionEditorGraphicsScene::setZoom(int scaleFactor) { - m_layout->setRulerScaleFactor(scaleFactor); + m_layout->setZoom(scaleFactor); setScrollOffset(0); invalidateSections(); @@ -209,6 +214,35 @@ void TransitionEditorGraphicsScene::setRulerScaling(int scaleFactor) update(); } +void TransitionEditorGraphicsScene::setZoom(int scaling, double pivot) +{ + const qreal oldOffset = scrollOffset(); + const qreal oldScaling = m_layout->rulerScaling(); + const qreal oldPosition = mapToScene(pivot); + m_layout->setZoom(scaling); + + const qreal newScaling = m_layout->rulerScaling(); + const qreal newPosition = mapToScene(pivot); + + const qreal newOffset = oldOffset + (newPosition - oldPosition); + + if (std::isinf(oldScaling) || std::isinf(newScaling)) + setScrollOffset(0); + else { + setScrollOffset(std::round(newOffset)); + + const qreal start = mapToScene(startFrame()); + const qreal head = TimelineConstants::sectionWidth + TimelineConstants::timelineLeftOffset; + + if (start - head > 0) + setScrollOffset(0); + } + + invalidateSections(); + invalidateScrollbar(); + update(); +} + void TransitionEditorGraphicsScene::invalidateSectionForTarget(const ModelNode &target) { if (!target.isValid()) diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h index d7174df55a6..d0ade7064ca 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorgraphicsscene.h @@ -81,6 +81,7 @@ public: TransitionEditorWidget *transitionEditorWidget() const; TransitionEditorToolBar *toolBar() const; + int zoom() const override; qreal rulerScaling() const override; int rulerWidth() const override; qreal rulerDuration() const override; @@ -90,7 +91,8 @@ public: qreal mapToScene(qreal x) const; qreal mapFromScene(qreal x) const; - void setRulerScaling(int scaling); + void setZoom(int scaling); + void setZoom(int scaling, double pivot); void invalidateSectionForTarget(const ModelNode &modelNode); void invalidateHeightForTarget(const ModelNode &modelNode); diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp index 3d7e4ec4216..b2cb67c988d 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.cpp @@ -29,6 +29,7 @@ #include "transitioneditorpropertyitem.h" #include "transitioneditortoolbar.h" #include "transitioneditorview.h" +#include "navigation2d.h" #include #include @@ -63,6 +64,8 @@ #include #include +#include + namespace QmlDesigner { class Eventfilter : public QObject @@ -87,7 +90,7 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view) , m_toolbar(new TransitionEditorToolBar(this)) , m_rulerView(new QGraphicsView(this)) , m_graphicsView(new QGraphicsView(this)) - , m_scrollbar(new QScrollBar(this)) + , m_scrollbar(new Navigation2dScrollBar(this)) , m_statusBar(new QLabel(this)) , m_transitionEditorView(view) , m_graphicsScene(new TransitionEditorGraphicsScene(this)) @@ -126,6 +129,7 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view) m_graphicsView->setFrameShape(QFrame::NoFrame); m_graphicsView->setFrameShadow(QFrame::Plain); m_graphicsView->setLineWidth(0); + m_graphicsView->setVerticalScrollBar(new Navigation2dScrollBar); m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -218,6 +222,14 @@ TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view) connect(m_addButton, &QPushButton::clicked, this, [this]() { m_transitionEditorView->addNewTransition(); }); + + Navigation2dFilter *filter = new Navigation2dFilter(this, m_scrollbar); + connect(filter, &Navigation2dFilter::zoomChanged, [this](double scale, const QPointF& pos) { + int s = static_cast(std::round(scale*100.)); + double ps = m_graphicsScene->mapFromScene(pos.x()); + m_graphicsScene->setZoom(std::clamp(m_graphicsScene->zoom() + s, 0, 100), ps); + }); + installEventFilter(filter); } void TransitionEditorWidget::setTransitionActive(bool b) @@ -258,7 +270,7 @@ void TransitionEditorWidget::connectToolbar() this, &TransitionEditorWidget::scroll); - auto setRulerScaling = [this](int val) { m_graphicsScene->setRulerScaling(val); }; + auto setRulerScaling = [this](int val) { m_graphicsScene->setZoom(val); }; connect(m_toolbar, &TransitionEditorToolBar::scaleFactorChanged, setRulerScaling); auto setDuration = [this](int end) { graphicsScene()->setDuration(end); }; @@ -335,7 +347,7 @@ void TransitionEditorWidget::init() m_toolbar->setDuration(duration); - m_graphicsScene->setRulerScaling(40); + m_graphicsScene->setZoom(40); } void TransitionEditorWidget::updateData(const ModelNode &transition) diff --git a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.h b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.h index dbbe87a1ffd..f1c4174418a 100644 --- a/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.h +++ b/src/plugins/qmldesigner/components/transitioneditor/transitioneditorwidget.h @@ -37,7 +37,6 @@ QT_FORWARD_DECLARE_CLASS(QComboBox) QT_FORWARD_DECLARE_CLASS(QGraphicsView) QT_FORWARD_DECLARE_CLASS(QLabel) QT_FORWARD_DECLARE_CLASS(QResizeEvent) -QT_FORWARD_DECLARE_CLASS(QScrollBar) QT_FORWARD_DECLARE_CLASS(QShowEvent) QT_FORWARD_DECLARE_CLASS(QString) QT_FORWARD_DECLARE_CLASS(QPushButton) @@ -48,6 +47,7 @@ class TransitionEditorView; class TransitionEditorToolBar; class TransitionEditorGraphicsScene; class ModelNode; +class Navigation2dScrollBar; class TransitionEditorWidget : public QWidget { @@ -88,7 +88,7 @@ private: QGraphicsView *m_graphicsView = nullptr; - QScrollBar *m_scrollbar = nullptr; + Navigation2dScrollBar *m_scrollbar = nullptr; QLabel *m_statusBar = nullptr; diff --git a/src/plugins/qmldesigner/qmldesignerplugin.qbs b/src/plugins/qmldesigner/qmldesignerplugin.qbs index ea57599bd08..a4e22d75200 100644 --- a/src/plugins/qmldesigner/qmldesignerplugin.qbs +++ b/src/plugins/qmldesigner/qmldesignerplugin.qbs @@ -446,6 +446,8 @@ Project { "componentcore/modelnodecontextmenu_helper.h", "componentcore/modelnodeoperations.cpp", "componentcore/modelnodeoperations.h", + "componentcore/navigation2d.cpp", + "componentcore/navigation2d.h", "componentcore/selectioncontext.cpp", "componentcore/selectioncontext.h", "componentcore/qmldesignericonprovider.cpp",