forked from qt-creator/qt-creator
QmlDesigner: First implementation of TransitionEditor
Change-Id: I14391e872f6a257a2cdf75e7d577de64c384c1fd Reviewed-by: Tim Jenssen <tim.jenssen@qt.io> Reviewed-by: Henning Gründl <henning.gruendl@qt.io> Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io>
This commit is contained in:
@@ -668,6 +668,22 @@ extend_qtc_plugin(QmlDesigner
|
|||||||
timelinewidget.cpp timelinewidget.h
|
timelinewidget.cpp timelinewidget.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
extend_qtc_plugin(QmlDesigner
|
||||||
|
SOURCES_PREFIX components/transitioneditor
|
||||||
|
SOURCES
|
||||||
|
transitioneditorview.cpp transitioneditorview.h
|
||||||
|
transitioneditorwidget.cpp transitioneditorwidget.h
|
||||||
|
transitioneditortoolbar.cpp transitioneditortoolbar.h
|
||||||
|
transitioneditorgraphicsscene.cpp transitioneditorgraphicsscene.h
|
||||||
|
transitioneditorgraphicslayout.cpp transitioneditorgraphicslayout.h
|
||||||
|
transitioneditorsectionitem.cpp transitioneditorsectionitem.h
|
||||||
|
transitioneditorpropertyitem.cpp transitioneditorpropertyitem.h
|
||||||
|
transitioneditorsettingsdialog.cpp transitioneditorsettingsdialog.h
|
||||||
|
transitioneditorsettingsdialog.ui
|
||||||
|
transitionform.cpp transitionform.h
|
||||||
|
transitioneditor.qrc
|
||||||
|
)
|
||||||
|
|
||||||
extend_qtc_plugin(QmlDesigner
|
extend_qtc_plugin(QmlDesigner
|
||||||
SOURCES_PREFIX components/curveeditor
|
SOURCES_PREFIX components/curveeditor
|
||||||
SOURCES
|
SOURCES
|
||||||
|
@@ -0,0 +1,35 @@
|
|||||||
|
QT *= qml quick core
|
||||||
|
|
||||||
|
VPATH += $$PWD
|
||||||
|
|
||||||
|
INCLUDEPATH += $$PWD
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
transitioneditorview.cpp \
|
||||||
|
transitioneditorwidget.cpp \
|
||||||
|
transitioneditortoolbar.cpp \
|
||||||
|
transitioneditorgraphicsscene.cpp \
|
||||||
|
transitioneditorgraphicslayout.cpp \
|
||||||
|
transitioneditorsectionitem.cpp \
|
||||||
|
transitioneditorpropertyitem.cpp \
|
||||||
|
transitioneditorsettingsdialog.cpp \
|
||||||
|
transitionform.cpp
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
transitioneditorconstants \
|
||||||
|
transitioneditorview.h \
|
||||||
|
transitioneditorwidget.h \
|
||||||
|
transitioneditortoolbar.h \
|
||||||
|
transitioneditorgraphicsscene.h \
|
||||||
|
transitioneditorgraphicslayout.h \
|
||||||
|
transitioneditorsectionitem.h \
|
||||||
|
transitioneditorpropertyitem.h \
|
||||||
|
transitioneditorsettingsdialog.h \
|
||||||
|
transitionform.h
|
||||||
|
|
||||||
|
RESOURCES += \
|
||||||
|
transitioneditor.qrc
|
||||||
|
|
||||||
|
FORMS += \
|
||||||
|
transitioneditorsettingsdialog.ui \
|
||||||
|
transitionform.ui
|
@@ -0,0 +1,4 @@
|
|||||||
|
<RCC>
|
||||||
|
<qresource prefix="/transitioneditor">
|
||||||
|
</qresource>
|
||||||
|
</RCC>
|
@@ -0,0 +1,37 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2019 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 <QGraphicsItem>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
namespace TransitionEditorConstants {
|
||||||
|
|
||||||
|
const int transitionEditorSectionItemUserType = QGraphicsItem::UserType + 6;
|
||||||
|
const int transitionEditorPropertyItemUserType = QGraphicsItem::UserType + 7;
|
||||||
|
|
||||||
|
} // namespace TransitionEditorConstants
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,172 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorgraphicslayout.h"
|
||||||
|
|
||||||
|
#include "timelinegraphicsscene.h"
|
||||||
|
#include "timelineplaceholder.h"
|
||||||
|
#include "timelinesectionitem.h"
|
||||||
|
#include "timelineview.h"
|
||||||
|
#include "transitioneditorsectionitem.h"
|
||||||
|
|
||||||
|
#include <QGraphicsLinearLayout>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
TransitionEditorGraphicsLayout::TransitionEditorGraphicsLayout(QGraphicsScene *scene,
|
||||||
|
TimelineItem *parent)
|
||||||
|
: TimelineItem(parent)
|
||||||
|
, m_layout(new QGraphicsLinearLayout)
|
||||||
|
, m_rulerItem(TimelineRulerSectionItem::create(scene, this))
|
||||||
|
, m_placeholder1(TimelinePlaceholder::create(scene, this))
|
||||||
|
, m_placeholder2(TimelinePlaceholder::create(scene, this))
|
||||||
|
{
|
||||||
|
m_layout->setOrientation(Qt::Vertical);
|
||||||
|
m_layout->setSpacing(0);
|
||||||
|
m_layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
||||||
|
m_layout->addItem(m_rulerItem);
|
||||||
|
m_layout->addItem(m_placeholder1);
|
||||||
|
m_layout->addItem(m_placeholder2);
|
||||||
|
|
||||||
|
setLayout(m_layout);
|
||||||
|
|
||||||
|
setPos(QPointF(0, 0));
|
||||||
|
|
||||||
|
connect(m_rulerItem,
|
||||||
|
&TimelineRulerSectionItem::rulerClicked,
|
||||||
|
this,
|
||||||
|
&TransitionEditorGraphicsLayout::rulerClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorGraphicsLayout::~TransitionEditorGraphicsLayout() = default;
|
||||||
|
|
||||||
|
double TransitionEditorGraphicsLayout::rulerWidth() const
|
||||||
|
{
|
||||||
|
return m_rulerItem->preferredWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
double TransitionEditorGraphicsLayout::rulerScaling() const
|
||||||
|
{
|
||||||
|
return m_rulerItem->rulerScaling();
|
||||||
|
}
|
||||||
|
|
||||||
|
double TransitionEditorGraphicsLayout::rulerDuration() const
|
||||||
|
{
|
||||||
|
return m_rulerItem->rulerDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
double TransitionEditorGraphicsLayout::endFrame() const
|
||||||
|
{
|
||||||
|
return m_rulerItem->endFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsLayout::setWidth(int width)
|
||||||
|
{
|
||||||
|
m_rulerItem->setSizeHints(width);
|
||||||
|
m_placeholder1->setMinimumWidth(width);
|
||||||
|
m_placeholder2->setMinimumWidth(width);
|
||||||
|
setPreferredWidth(width);
|
||||||
|
setMaximumWidth(width);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsLayout::setTransition(const ModelNode &transition)
|
||||||
|
{
|
||||||
|
m_layout->removeItem(m_rulerItem);
|
||||||
|
m_layout->removeItem(m_placeholder1);
|
||||||
|
m_layout->removeItem(m_placeholder2);
|
||||||
|
|
||||||
|
m_rulerItem->setParentItem(nullptr);
|
||||||
|
m_placeholder1->setParentItem(nullptr);
|
||||||
|
m_placeholder2->setParentItem(nullptr);
|
||||||
|
|
||||||
|
qDeleteAll(this->childItems());
|
||||||
|
|
||||||
|
m_rulerItem->setParentItem(this);
|
||||||
|
|
||||||
|
qreal duration = 2000;
|
||||||
|
if (transition.isValid() && transition.hasAuxiliaryData("transitionDuration"))
|
||||||
|
duration = transition.auxiliaryData("transitionDuration").toDouble();
|
||||||
|
|
||||||
|
setDuration(duration);
|
||||||
|
m_layout->addItem(m_rulerItem);
|
||||||
|
|
||||||
|
m_placeholder1->setParentItem(this);
|
||||||
|
m_layout->addItem(m_placeholder1);
|
||||||
|
|
||||||
|
m_layout->invalidate();
|
||||||
|
|
||||||
|
if (transition.isValid() && !transition.directSubModelNodes().isEmpty()) {
|
||||||
|
for (const ModelNode ¶llel : transition.directSubModelNodes()) {
|
||||||
|
auto item = TransitionEditorSectionItem::create(parallel, this);
|
||||||
|
m_layout->addItem(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_placeholder2->setParentItem(this);
|
||||||
|
m_layout->addItem(m_placeholder2);
|
||||||
|
|
||||||
|
if (auto *scene = timelineScene())
|
||||||
|
if (auto *view = scene->timelineView())
|
||||||
|
if (!transition.isValid() && view->isAttached())
|
||||||
|
emit scaleFactorChanged(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsLayout::setDuration(qreal duration)
|
||||||
|
{
|
||||||
|
m_rulerItem->invalidateRulerSize(duration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsLayout::setRulerScaleFactor(int factor)
|
||||||
|
{
|
||||||
|
m_rulerItem->setRulerScaleFactor(factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsLayout::invalidate()
|
||||||
|
{
|
||||||
|
m_layout->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransitionEditorGraphicsLayout::maximumScrollValue() const
|
||||||
|
{
|
||||||
|
const qreal w = this->geometry().width() - qreal(TimelineConstants::sectionWidth);
|
||||||
|
const qreal duration = m_rulerItem->rulerDuration() + m_rulerItem->rulerDuration() * 0.1;
|
||||||
|
const qreal maxr = m_rulerItem->rulerScaling() * duration - w;
|
||||||
|
return std::round(qMax(maxr, 0.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsLayout::activate()
|
||||||
|
{
|
||||||
|
m_layout->activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
TimelineRulerSectionItem *TransitionEditorGraphicsLayout::ruler() const
|
||||||
|
{
|
||||||
|
return m_rulerItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End namespace QmlDesigner.
|
@@ -0,0 +1,89 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "timelineitem.h"
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QGraphicsLinearLayout)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TimelineItem;
|
||||||
|
class TimelineRulerSectionItem;
|
||||||
|
class TimelinePlaceholder;
|
||||||
|
|
||||||
|
class ModelNode;
|
||||||
|
|
||||||
|
class TransitionEditorGraphicsLayout : public TimelineItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void rulerClicked(const QPointF &pos);
|
||||||
|
|
||||||
|
void scaleFactorChanged(int factor);
|
||||||
|
|
||||||
|
public:
|
||||||
|
TransitionEditorGraphicsLayout(QGraphicsScene *scene, TimelineItem *parent = nullptr);
|
||||||
|
|
||||||
|
~TransitionEditorGraphicsLayout() override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
double rulerWidth() const;
|
||||||
|
|
||||||
|
double rulerScaling() const;
|
||||||
|
|
||||||
|
double rulerDuration() const;
|
||||||
|
|
||||||
|
double endFrame() const;
|
||||||
|
|
||||||
|
void setWidth(int width);
|
||||||
|
|
||||||
|
void setTransition(const ModelNode &transition);
|
||||||
|
|
||||||
|
void setDuration(qreal duration);
|
||||||
|
|
||||||
|
void setRulerScaleFactor(int factor);
|
||||||
|
|
||||||
|
void invalidate();
|
||||||
|
|
||||||
|
int maximumScrollValue() const;
|
||||||
|
|
||||||
|
void activate();
|
||||||
|
|
||||||
|
TimelineRulerSectionItem *ruler() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QGraphicsLinearLayout *m_layout = nullptr;
|
||||||
|
|
||||||
|
TimelineRulerSectionItem *m_rulerItem = nullptr;
|
||||||
|
|
||||||
|
TimelinePlaceholder *m_placeholder1 = nullptr;
|
||||||
|
|
||||||
|
TimelinePlaceholder *m_placeholder2 = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,431 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorgraphicsscene.h"
|
||||||
|
|
||||||
|
#include "transitioneditorgraphicslayout.h"
|
||||||
|
#include "transitioneditorpropertyitem.h"
|
||||||
|
#include "transitioneditorsectionitem.h"
|
||||||
|
#include "transitioneditortoolbar.h"
|
||||||
|
#include "transitioneditorview.h"
|
||||||
|
#include "transitioneditorwidget.h"
|
||||||
|
|
||||||
|
#include "timelineactions.h"
|
||||||
|
#include "timelineitem.h"
|
||||||
|
#include "timelinemovableabstractitem.h"
|
||||||
|
#include "timelinemovetool.h"
|
||||||
|
#include "timelineplaceholder.h"
|
||||||
|
#include "timelinepropertyitem.h"
|
||||||
|
#include "timelinesectionitem.h"
|
||||||
|
|
||||||
|
#include <designdocumentview.h>
|
||||||
|
#include <exception.h>
|
||||||
|
#include <rewritertransaction.h>
|
||||||
|
#include <rewriterview.h>
|
||||||
|
#include <viewmanager.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <qmlobjectnode.h>
|
||||||
|
#include <qmltimelinekeyframegroup.h>
|
||||||
|
|
||||||
|
#include <bindingproperty.h>
|
||||||
|
|
||||||
|
#include <nodeabstractproperty.h>
|
||||||
|
#include <nodelistproperty.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <utils/hostosinfo.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QGraphicsLinearLayout>
|
||||||
|
#include <QGraphicsProxyWidget>
|
||||||
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <QGraphicsView>
|
||||||
|
#include <QKeyEvent>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
static int deleteKey()
|
||||||
|
{
|
||||||
|
if (Utils::HostOsInfo::isMacHost())
|
||||||
|
return Qt::Key_Backspace;
|
||||||
|
|
||||||
|
return Qt::Key_Delete;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorGraphicsScene::TransitionEditorGraphicsScene(TransitionEditorWidget *parent)
|
||||||
|
: AbstractScrollGraphicsScene(parent)
|
||||||
|
, m_parent(parent)
|
||||||
|
, m_layout(new TransitionEditorGraphicsLayout(this))
|
||||||
|
, m_tools(this)
|
||||||
|
{
|
||||||
|
addItem(m_layout);
|
||||||
|
|
||||||
|
setSceneRect(m_layout->geometry());
|
||||||
|
|
||||||
|
connect(m_layout, &QGraphicsWidget::geometryChanged, this, [this]() {
|
||||||
|
auto rect = m_layout->geometry();
|
||||||
|
|
||||||
|
setSceneRect(rect);
|
||||||
|
|
||||||
|
if (auto *gview = graphicsView())
|
||||||
|
gview->setSceneRect(rect.adjusted(0, TimelineConstants::rulerHeight, 0, 0));
|
||||||
|
|
||||||
|
if (auto *rview = rulerView())
|
||||||
|
rview->setSceneRect(rect);
|
||||||
|
});
|
||||||
|
|
||||||
|
auto changeScale = [this](int factor) {
|
||||||
|
transitionEditorWidget()->changeScaleFactor(factor);
|
||||||
|
setRulerScaling(qreal(factor));
|
||||||
|
};
|
||||||
|
connect(m_layout, &TransitionEditorGraphicsLayout::scaleFactorChanged, changeScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorGraphicsScene::~TransitionEditorGraphicsScene()
|
||||||
|
{
|
||||||
|
QSignalBlocker block(this);
|
||||||
|
qDeleteAll(items());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::invalidateScrollbar()
|
||||||
|
{
|
||||||
|
double max = m_layout->maximumScrollValue();
|
||||||
|
transitionEditorWidget()->setupScrollbar(0, max, scrollOffset());
|
||||||
|
if (scrollOffset() > max)
|
||||||
|
setScrollOffset(max);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::onShow()
|
||||||
|
{
|
||||||
|
emit m_layout->scaleFactorChanged(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::setTransition(const ModelNode &transition)
|
||||||
|
{
|
||||||
|
clearSelection();
|
||||||
|
m_layout->setTransition(transition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::clearTransition()
|
||||||
|
{
|
||||||
|
m_transition = {};
|
||||||
|
m_layout->setTransition({});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::setWidth(int width)
|
||||||
|
{
|
||||||
|
m_layout->setWidth(width);
|
||||||
|
invalidateScrollbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::invalidateLayout()
|
||||||
|
{
|
||||||
|
m_layout->invalidate();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::setDuration(int duration)
|
||||||
|
{
|
||||||
|
if (m_transition.isValid())
|
||||||
|
m_transition.setAuxiliaryData("transitionDuration", duration);
|
||||||
|
m_layout->setDuration(duration);
|
||||||
|
qreal scaling = m_layout->rulerScaling();
|
||||||
|
setRulerScaling(scaling);
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorGraphicsScene::rulerScaling() const
|
||||||
|
{
|
||||||
|
return m_layout->rulerScaling();
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransitionEditorGraphicsScene::rulerWidth() const
|
||||||
|
{
|
||||||
|
return m_layout->rulerWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorGraphicsScene::rulerDuration() const
|
||||||
|
{
|
||||||
|
return m_layout->rulerDuration();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorGraphicsScene::endFrame() const
|
||||||
|
{
|
||||||
|
return m_layout->endFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorGraphicsScene::startFrame() const
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorGraphicsScene::mapToScene(qreal x) const
|
||||||
|
{
|
||||||
|
return TimelineConstants::sectionWidth + TimelineConstants::timelineLeftOffset
|
||||||
|
+ (x - startFrame()) * rulerScaling() - scrollOffset();
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorGraphicsScene::mapFromScene(qreal x) const
|
||||||
|
{
|
||||||
|
auto xPosOffset = (x - TimelineConstants::sectionWidth - TimelineConstants::timelineLeftOffset)
|
||||||
|
+ scrollOffset();
|
||||||
|
|
||||||
|
return xPosOffset / rulerScaling() + startFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::setRulerScaling(int scaleFactor)
|
||||||
|
{
|
||||||
|
m_layout->setRulerScaleFactor(scaleFactor);
|
||||||
|
|
||||||
|
setScrollOffset(0);
|
||||||
|
invalidateSections();
|
||||||
|
invalidateScrollbar();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::invalidateSectionForTarget(const ModelNode &target)
|
||||||
|
{
|
||||||
|
if (!target.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
const QList<QGraphicsItem *> items = m_layout->childItems();
|
||||||
|
for (auto child : items)
|
||||||
|
TimelineSectionItem::updateDataForTarget(child, target, &found);
|
||||||
|
|
||||||
|
if (!found)
|
||||||
|
invalidateScene();
|
||||||
|
|
||||||
|
clearSelection();
|
||||||
|
invalidateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::invalidateScene()
|
||||||
|
{
|
||||||
|
invalidateScrollbar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::invalidateCurrentValues()
|
||||||
|
{
|
||||||
|
const QList<QGraphicsItem *> constItems = items();
|
||||||
|
for (auto item : constItems)
|
||||||
|
TimelinePropertyItem::updateTextEdit(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
QGraphicsView *TransitionEditorGraphicsScene::graphicsView() const
|
||||||
|
{
|
||||||
|
const QList<QGraphicsView *> constViews = views();
|
||||||
|
for (auto *v : constViews)
|
||||||
|
if (v->objectName() == "SceneView")
|
||||||
|
return v;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGraphicsView *TransitionEditorGraphicsScene::rulerView() const
|
||||||
|
{
|
||||||
|
const QList<QGraphicsView *> constViews = views();
|
||||||
|
for (auto *v : constViews)
|
||||||
|
if (v->objectName() == "RulerView")
|
||||||
|
return v;
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QRectF TransitionEditorGraphicsScene::selectionBounds() const
|
||||||
|
{
|
||||||
|
QRectF bbox;
|
||||||
|
|
||||||
|
return bbox;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::clearSelection()
|
||||||
|
{
|
||||||
|
if (m_selectedProperty)
|
||||||
|
m_selectedProperty->update();
|
||||||
|
|
||||||
|
m_selectedProperty = nullptr;
|
||||||
|
AbstractScrollGraphicsScene::clearSelection();
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<QGraphicsItem *> TransitionEditorGraphicsScene::itemsAt(const QPointF &pos)
|
||||||
|
{
|
||||||
|
QTransform transform;
|
||||||
|
|
||||||
|
if (auto *gview = graphicsView())
|
||||||
|
transform = gview->transform();
|
||||||
|
|
||||||
|
return items(pos, Qt::IntersectsItemShape, Qt::DescendingOrder, transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
auto topItem = TimelineMovableAbstractItem::topMoveableItem(itemsAt(event->scenePos()));
|
||||||
|
|
||||||
|
m_tools.mousePressEvent(topItem, event);
|
||||||
|
QGraphicsScene::mousePressEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
auto topItem = TimelineMovableAbstractItem::topMoveableItem(itemsAt(event->scenePos()));
|
||||||
|
m_tools.mouseMoveEvent(topItem, event);
|
||||||
|
QGraphicsScene::mouseMoveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
auto topItem = TimelineMovableAbstractItem::topMoveableItem(itemsAt(event->scenePos()));
|
||||||
|
/* The tool has handle the event last. */
|
||||||
|
QGraphicsScene::mouseReleaseEvent(event);
|
||||||
|
m_tools.mouseReleaseEvent(topItem, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
auto topItem = TimelineMovableAbstractItem::topMoveableItem(itemsAt(event->scenePos()));
|
||||||
|
m_tools.mouseDoubleClickEvent(topItem, event);
|
||||||
|
QGraphicsScene::mouseDoubleClickEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::keyPressEvent(QKeyEvent *keyEvent)
|
||||||
|
{
|
||||||
|
if (qgraphicsitem_cast<QGraphicsProxyWidget *>(focusItem())) {
|
||||||
|
keyEvent->ignore();
|
||||||
|
QGraphicsScene::keyPressEvent(keyEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyEvent->modifiers().testFlag(Qt::ControlModifier)) {
|
||||||
|
QGraphicsScene::keyPressEvent(keyEvent);
|
||||||
|
} else {
|
||||||
|
switch (keyEvent->key()) {
|
||||||
|
case Qt::Key_Left:
|
||||||
|
emit scroll(TimelineUtils::Side::Left);
|
||||||
|
keyEvent->accept();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Qt::Key_Right:
|
||||||
|
emit scroll(TimelineUtils::Side::Right);
|
||||||
|
keyEvent->accept();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
QGraphicsScene::keyPressEvent(keyEvent);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::keyReleaseEvent(QKeyEvent *keyEvent)
|
||||||
|
{
|
||||||
|
if (qgraphicsitem_cast<QGraphicsProxyWidget *>(focusItem())) {
|
||||||
|
keyEvent->ignore();
|
||||||
|
QGraphicsScene::keyReleaseEvent(keyEvent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGraphicsScene::keyReleaseEvent(keyEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::invalidateSections()
|
||||||
|
{
|
||||||
|
const QList<QGraphicsItem *> children = m_layout->childItems();
|
||||||
|
for (auto child : children)
|
||||||
|
TransitionEditorSectionItem::updateData(child);
|
||||||
|
|
||||||
|
clearSelection();
|
||||||
|
invalidateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorView *TransitionEditorGraphicsScene::transitionEditorView() const
|
||||||
|
{
|
||||||
|
return m_parent->transitionEditorView();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorWidget *TransitionEditorGraphicsScene::transitionEditorWidget() const
|
||||||
|
{
|
||||||
|
return m_parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorToolBar *TransitionEditorGraphicsScene::toolBar() const
|
||||||
|
{
|
||||||
|
return transitionEditorWidget()->toolBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::activateLayout()
|
||||||
|
{
|
||||||
|
m_layout->activate();
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractView *TransitionEditorGraphicsScene::abstractView() const
|
||||||
|
{
|
||||||
|
return transitionEditorView();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorGraphicsScene::event(QEvent *event)
|
||||||
|
{
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::ShortcutOverride:
|
||||||
|
if (static_cast<QKeyEvent *>(event)->key() == deleteKey()) {
|
||||||
|
QGraphicsScene::keyPressEvent(static_cast<QKeyEvent *>(event));
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
Q_FALLTHROUGH();
|
||||||
|
default:
|
||||||
|
return QGraphicsScene::event(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode TransitionEditorGraphicsScene::transitionModelNode() const
|
||||||
|
{
|
||||||
|
if (transitionEditorView()->isAttached()) {
|
||||||
|
const QString timelineId = transitionEditorWidget()->toolBar()->currentTransitionId();
|
||||||
|
return transitionEditorView()->modelNodeForId(timelineId);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ModelNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorPropertyItem *TransitionEditorGraphicsScene::selectedPropertyItem() const
|
||||||
|
{
|
||||||
|
return m_selectedProperty;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorGraphicsScene::setSelectedPropertyItem(TransitionEditorPropertyItem *item)
|
||||||
|
{
|
||||||
|
if (m_selectedProperty)
|
||||||
|
m_selectedProperty->update();
|
||||||
|
m_selectedProperty = item;
|
||||||
|
emit selectionChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,146 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <timelineeditor/timelinegraphicsscene.h>
|
||||||
|
|
||||||
|
#include <qmltimeline.h>
|
||||||
|
|
||||||
|
#include <QGraphicsScene>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QGraphicsLinearLayout)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QComboBox)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TransitionEditorView;
|
||||||
|
class TransitionEditorWidget;
|
||||||
|
class TransitionEditorToolBar;
|
||||||
|
class TransitionEditorGraphicsLayout;
|
||||||
|
|
||||||
|
class TimelineRulerSectionItem;
|
||||||
|
class TimelineFrameHandle;
|
||||||
|
class TimelineAbstractTool;
|
||||||
|
class TimelineMoveTool;
|
||||||
|
class TimelineKeyframeItem;
|
||||||
|
class TimelinePlaceholder;
|
||||||
|
class TimelineToolBar;
|
||||||
|
class TransitionEditorPropertyItem;
|
||||||
|
|
||||||
|
class TransitionEditorGraphicsScene : public AbstractScrollGraphicsScene
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void selectionChanged();
|
||||||
|
|
||||||
|
void scroll(const TimelineUtils::Side &side);
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransitionEditorGraphicsScene(TransitionEditorWidget *parent);
|
||||||
|
|
||||||
|
~TransitionEditorGraphicsScene() override;
|
||||||
|
|
||||||
|
void onShow();
|
||||||
|
|
||||||
|
void setTransition(const ModelNode &transition);
|
||||||
|
void clearTransition();
|
||||||
|
|
||||||
|
void setWidth(int width);
|
||||||
|
|
||||||
|
void invalidateLayout();
|
||||||
|
void setDuration(int duration);
|
||||||
|
|
||||||
|
TransitionEditorView *transitionEditorView() const;
|
||||||
|
TransitionEditorWidget *transitionEditorWidget() const;
|
||||||
|
TransitionEditorToolBar *toolBar() const;
|
||||||
|
|
||||||
|
qreal rulerScaling() const override;
|
||||||
|
int rulerWidth() const override;
|
||||||
|
qreal rulerDuration() const override;
|
||||||
|
qreal endFrame() const override;
|
||||||
|
qreal startFrame() const override;
|
||||||
|
|
||||||
|
qreal mapToScene(qreal x) const;
|
||||||
|
qreal mapFromScene(qreal x) const;
|
||||||
|
|
||||||
|
void setRulerScaling(int scaling);
|
||||||
|
|
||||||
|
void invalidateSectionForTarget(const ModelNode &modelNode);
|
||||||
|
|
||||||
|
void invalidateScene();
|
||||||
|
void invalidateCurrentValues();
|
||||||
|
void invalidateRecordButtonsStatus();
|
||||||
|
|
||||||
|
QGraphicsView *graphicsView() const;
|
||||||
|
QGraphicsView *rulerView() const;
|
||||||
|
|
||||||
|
QRectF selectionBounds() const;
|
||||||
|
|
||||||
|
void selectKeyframes(const SelectionMode &mode, const QList<TimelineKeyframeItem *> &items);
|
||||||
|
void clearSelection() override;
|
||||||
|
|
||||||
|
void activateLayout();
|
||||||
|
|
||||||
|
AbstractView *abstractView() const override;
|
||||||
|
ModelNode transitionModelNode() const;
|
||||||
|
|
||||||
|
TransitionEditorPropertyItem *selectedPropertyItem() const;
|
||||||
|
void setSelectedPropertyItem(TransitionEditorPropertyItem *item);
|
||||||
|
|
||||||
|
void invalidateScrollbar() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void statusBarMessageChanged(const QString &message);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool event(QEvent *event) override;
|
||||||
|
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
|
||||||
|
void keyPressEvent(QKeyEvent *keyEvent) override;
|
||||||
|
void keyReleaseEvent(QKeyEvent *keyEvent) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void invalidateSections();
|
||||||
|
QList<QGraphicsItem *> itemsAt(const QPointF &pos);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TransitionEditorWidget *m_parent = nullptr;
|
||||||
|
TransitionEditorGraphicsLayout *m_layout = nullptr;
|
||||||
|
ModelNode m_transition;
|
||||||
|
|
||||||
|
int m_scrollOffset = 0;
|
||||||
|
TimelineToolDelegate m_tools;
|
||||||
|
TransitionEditorPropertyItem *m_selectedProperty = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,237 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorpropertyitem.h"
|
||||||
|
|
||||||
|
#include "abstractview.h"
|
||||||
|
#include "timelineconstants.h"
|
||||||
|
#include "timelineicons.h"
|
||||||
|
#include "transitioneditorgraphicsscene.h"
|
||||||
|
|
||||||
|
#include <bindingproperty.h>
|
||||||
|
#include <nodeabstractproperty.h>
|
||||||
|
#include <rewritertransaction.h>
|
||||||
|
#include <rewritingexception.h>
|
||||||
|
#include <theme.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
#include <qmlobjectnode.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/utilsicons.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <QCursor>
|
||||||
|
#include <QGraphicsProxyWidget>
|
||||||
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <QGraphicsView>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QPainter>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
TransitionEditorPropertyItem *TransitionEditorPropertyItem::create(
|
||||||
|
const ModelNode &animation, TransitionEditorSectionItem *parent)
|
||||||
|
{
|
||||||
|
auto item = new TransitionEditorPropertyItem(parent);
|
||||||
|
item->m_animation = animation;
|
||||||
|
|
||||||
|
auto sectionItem = new QGraphicsWidget(item);
|
||||||
|
|
||||||
|
sectionItem->setGeometry(0,
|
||||||
|
0,
|
||||||
|
TimelineConstants::sectionWidth,
|
||||||
|
TimelineConstants::sectionHeight);
|
||||||
|
|
||||||
|
sectionItem->setZValue(10);
|
||||||
|
sectionItem->setCursor(Qt::ArrowCursor);
|
||||||
|
|
||||||
|
item->setToolTip(item->propertyName());
|
||||||
|
item->resize(parent->size());
|
||||||
|
|
||||||
|
item->m_barItem = new TransitionEditorBarItem(item);
|
||||||
|
item->invalidateBar();
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransitionEditorPropertyItem::type() const
|
||||||
|
{
|
||||||
|
return Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorPropertyItem::updateData()
|
||||||
|
{
|
||||||
|
invalidateBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorPropertyItem::updateParentData()
|
||||||
|
{
|
||||||
|
TransitionEditorSectionItem::invalidateBar(parentItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorPropertyItem::isSelected() const
|
||||||
|
{
|
||||||
|
return transitionEditorGraphicsScene()->selectedPropertyItem() == this;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TransitionEditorPropertyItem::propertyName() const
|
||||||
|
{
|
||||||
|
if (m_animation.isValid()) {
|
||||||
|
const QString propertyName = m_animation.variantProperty("property").value().toString();
|
||||||
|
if (!propertyName.isEmpty())
|
||||||
|
return propertyName;
|
||||||
|
return m_animation.variantProperty("properties").value().toString();
|
||||||
|
}
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorPropertyItem::paint(QPainter *painter,
|
||||||
|
const QStyleOptionGraphicsItem *,
|
||||||
|
QWidget *)
|
||||||
|
{
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
static const QColor penColor = Theme::instance()->qmlDesignerBackgroundColorDarker();
|
||||||
|
static const QColor textColor = Theme::getColor(Theme::PanelTextColorLight);
|
||||||
|
static const QColor backgroundColor = Theme::instance()
|
||||||
|
->qmlDesignerBackgroundColorDarkAlternate();
|
||||||
|
|
||||||
|
painter->fillRect(0, 0, TimelineConstants::sectionWidth, size().height(), backgroundColor);
|
||||||
|
painter->fillRect(TimelineConstants::textIndentationProperties - 4,
|
||||||
|
0,
|
||||||
|
TimelineConstants::sectionWidth - TimelineConstants::textIndentationProperties
|
||||||
|
+ 4,
|
||||||
|
size().height(),
|
||||||
|
backgroundColor.darker(110));
|
||||||
|
|
||||||
|
painter->setPen(penColor);
|
||||||
|
|
||||||
|
drawLine(painter,
|
||||||
|
TimelineConstants::sectionWidth - 1,
|
||||||
|
0,
|
||||||
|
TimelineConstants::sectionWidth - 1,
|
||||||
|
size().height());
|
||||||
|
|
||||||
|
drawLine(painter,
|
||||||
|
TimelineConstants::textIndentationProperties - 4,
|
||||||
|
TimelineConstants::sectionHeight - 1,
|
||||||
|
size().width(),
|
||||||
|
TimelineConstants::sectionHeight - 1);
|
||||||
|
|
||||||
|
painter->setPen(textColor);
|
||||||
|
|
||||||
|
const QFontMetrics metrics(font());
|
||||||
|
|
||||||
|
const QString elidedText = metrics.elidedText(propertyName(),
|
||||||
|
Qt::ElideMiddle,
|
||||||
|
qreal(TimelineConstants::sectionWidth) * 2.0 / 3
|
||||||
|
- TimelineConstants::textIndentationProperties,
|
||||||
|
0);
|
||||||
|
|
||||||
|
painter->drawText(TimelineConstants::textIndentationProperties, 12, elidedText);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorPropertyItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * /*event */) {}
|
||||||
|
|
||||||
|
TransitionEditorPropertyItem::TransitionEditorPropertyItem(TransitionEditorSectionItem *parent)
|
||||||
|
: TimelineItem(parent)
|
||||||
|
{
|
||||||
|
setPreferredHeight(TimelineConstants::sectionHeight);
|
||||||
|
setMinimumHeight(TimelineConstants::sectionHeight);
|
||||||
|
setMaximumHeight(TimelineConstants::sectionHeight);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorGraphicsScene *TransitionEditorPropertyItem::transitionEditorGraphicsScene() const
|
||||||
|
{
|
||||||
|
return qobject_cast<TransitionEditorGraphicsScene *>(scene());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorPropertyItem::invalidateBar()
|
||||||
|
{
|
||||||
|
qreal min = 0;
|
||||||
|
qreal max = 0;
|
||||||
|
|
||||||
|
QTC_ASSERT(m_animation.isValid(), return );
|
||||||
|
QTC_ASSERT(m_animation.hasParentProperty(), return );
|
||||||
|
|
||||||
|
const ModelNode parent = m_animation.parentProperty().parentModelNode();
|
||||||
|
|
||||||
|
for (const ModelNode &child : parent.directSubModelNodes())
|
||||||
|
if (child.hasMetaInfo() && child.isSubclassOf("QtQuick.PauseAnimation"))
|
||||||
|
min = child.variantProperty("duration").value().toDouble();
|
||||||
|
|
||||||
|
max = m_animation.variantProperty("duration").value().toDouble() + min;
|
||||||
|
|
||||||
|
const qreal sceneMin = m_barItem->mapFromFrameToScene(min);
|
||||||
|
|
||||||
|
QRectF barRect(sceneMin,
|
||||||
|
0,
|
||||||
|
(max - min) * m_barItem->rulerScaling(),
|
||||||
|
TimelineConstants::sectionHeight - 1);
|
||||||
|
|
||||||
|
m_barItem->setRect(barRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractView *TransitionEditorPropertyItem::view() const
|
||||||
|
{
|
||||||
|
return m_animation.view();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode TransitionEditorPropertyItem::propertyAnimation() const
|
||||||
|
{
|
||||||
|
return m_animation;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode TransitionEditorPropertyItem::pauseAnimation() const
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_animation.isValid(), return {});
|
||||||
|
QTC_ASSERT(m_animation.hasParentProperty(), return {});
|
||||||
|
|
||||||
|
const ModelNode parent = m_animation.parentProperty().parentModelNode();
|
||||||
|
|
||||||
|
for (const ModelNode &child : parent.directSubModelNodes())
|
||||||
|
if (child.hasMetaInfo() && child.isSubclassOf("QtQuick.PauseAnimation"))
|
||||||
|
return child;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorPropertyItem::select()
|
||||||
|
{
|
||||||
|
transitionEditorGraphicsScene()->setSelectedPropertyItem(this);
|
||||||
|
m_barItem->update();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,73 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorsectionitem.h"
|
||||||
|
|
||||||
|
#include <modelnode.h>
|
||||||
|
|
||||||
|
#include <QGraphicsRectItem>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QLineEdit)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TransitionEditorGraphicsScene;
|
||||||
|
|
||||||
|
class TransitionEditorPropertyItem : public TimelineItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { Type = TransitionEditorConstants::transitionEditorPropertyItemUserType };
|
||||||
|
|
||||||
|
static TransitionEditorPropertyItem *create(const ModelNode &animation,
|
||||||
|
TransitionEditorSectionItem *parent = nullptr);
|
||||||
|
int type() const override;
|
||||||
|
void updateData();
|
||||||
|
void updateParentData();
|
||||||
|
|
||||||
|
bool isSelected() const;
|
||||||
|
QString propertyName() const;
|
||||||
|
void invalidateBar();
|
||||||
|
AbstractView *view() const;
|
||||||
|
ModelNode propertyAnimation() const;
|
||||||
|
ModelNode pauseAnimation() const;
|
||||||
|
void select();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
|
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TransitionEditorPropertyItem(TransitionEditorSectionItem *parent = nullptr);
|
||||||
|
TransitionEditorGraphicsScene *transitionEditorGraphicsScene() const;
|
||||||
|
|
||||||
|
ModelNode m_animation;
|
||||||
|
TransitionEditorBarItem *m_barItem;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,803 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorsectionitem.h"
|
||||||
|
#include "transitioneditorgraphicsscene.h"
|
||||||
|
#include "transitioneditorpropertyitem.h"
|
||||||
|
|
||||||
|
#include "timelineactions.h"
|
||||||
|
#include "timelineconstants.h"
|
||||||
|
#include "timelineicons.h"
|
||||||
|
#include "timelinepropertyitem.h"
|
||||||
|
#include "timelineutils.h"
|
||||||
|
|
||||||
|
#include <abstractview.h>
|
||||||
|
#include <bindingproperty.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
#include <qmltimeline.h>
|
||||||
|
#include <qmltimelinekeyframegroup.h>
|
||||||
|
|
||||||
|
#include <rewritingexception.h>
|
||||||
|
|
||||||
|
#include <theme.h>
|
||||||
|
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QAction>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QColorDialog>
|
||||||
|
#include <QGraphicsScene>
|
||||||
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <QGraphicsView>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QMenu>
|
||||||
|
#include <QPainter>
|
||||||
|
#include <QPainterPath>
|
||||||
|
|
||||||
|
#include <QGraphicsView>
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
static void scaleDuration(const ModelNode &node, qreal s)
|
||||||
|
{
|
||||||
|
if (node.hasVariantProperty("duration")) {
|
||||||
|
qreal old = node.variantProperty("duration").value().toDouble();
|
||||||
|
node.variantProperty("duration").setValue(qRound(old * s));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void moveDuration(const ModelNode &node, qreal s)
|
||||||
|
{
|
||||||
|
if (node.hasVariantProperty("duration")) {
|
||||||
|
qreal old = node.variantProperty("duration").value().toDouble();
|
||||||
|
node.variantProperty("duration").setValue(old + s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ClickDummy : public TimelineItem
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit ClickDummy(TransitionEditorSectionItem *parent)
|
||||||
|
: TimelineItem(parent)
|
||||||
|
{
|
||||||
|
setGeometry(0, 0, TimelineConstants::sectionWidth, TimelineConstants::sectionHeight);
|
||||||
|
|
||||||
|
setZValue(10);
|
||||||
|
setCursor(Qt::ArrowCursor);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override
|
||||||
|
{
|
||||||
|
scene()->sendEvent(parentItem(), event);
|
||||||
|
}
|
||||||
|
void mousePressEvent(QGraphicsSceneMouseEvent *event) override
|
||||||
|
{
|
||||||
|
scene()->sendEvent(parentItem(), event);
|
||||||
|
}
|
||||||
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
|
||||||
|
{
|
||||||
|
scene()->sendEvent(parentItem(), event);
|
||||||
|
}
|
||||||
|
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override
|
||||||
|
{
|
||||||
|
scene()->sendEvent(parentItem(), event);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TransitionEditorSectionItem::TransitionEditorSectionItem(TimelineItem *parent)
|
||||||
|
: TimelineItem(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
TransitionEditorSectionItem *TransitionEditorSectionItem::create(const ModelNode &animation,
|
||||||
|
TimelineItem *parent)
|
||||||
|
{
|
||||||
|
auto item = new TransitionEditorSectionItem(parent);
|
||||||
|
|
||||||
|
ModelNode target;
|
||||||
|
|
||||||
|
if (animation.isValid()) {
|
||||||
|
const QList<ModelNode> propertyAnimations = animation.subModelNodesOfType(
|
||||||
|
"QtQuick.PropertyAnimation");
|
||||||
|
|
||||||
|
for (const ModelNode &child : propertyAnimations) {
|
||||||
|
if (child.hasBindingProperty("target"))
|
||||||
|
target = child.bindingProperty("target").resolveToModelNode();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
item->m_targetNode = target;
|
||||||
|
item->m_animationNode = animation;
|
||||||
|
item->createPropertyItems();
|
||||||
|
|
||||||
|
if (target.isValid())
|
||||||
|
item->setToolTip(target.id());
|
||||||
|
|
||||||
|
item->m_dummyItem = new ClickDummy(item);
|
||||||
|
item->m_dummyItem->update();
|
||||||
|
|
||||||
|
item->m_barItem = new TransitionEditorBarItem(item);
|
||||||
|
item->invalidateBar();
|
||||||
|
item->invalidateHeight();
|
||||||
|
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::invalidateBar()
|
||||||
|
{
|
||||||
|
qreal min = std::numeric_limits<qreal>::max();
|
||||||
|
qreal max = 0;
|
||||||
|
|
||||||
|
if (!m_animationNode.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (const ModelNode &sequential : m_animationNode.directSubModelNodes()) {
|
||||||
|
qreal locMin = 0;
|
||||||
|
qreal locMax = 0;
|
||||||
|
|
||||||
|
for (const ModelNode &child : sequential.directSubModelNodes()) {
|
||||||
|
if (child.hasMetaInfo() && child.isSubclassOf("QtQuick.PropertyAnimation"))
|
||||||
|
locMax = child.variantProperty("duration").value().toDouble();
|
||||||
|
else if (child.hasMetaInfo() && child.isSubclassOf("QtQuick.PauseAnimation"))
|
||||||
|
locMin = child.variantProperty("duration").value().toDouble();
|
||||||
|
}
|
||||||
|
|
||||||
|
locMax = locMax + locMin;
|
||||||
|
|
||||||
|
min = qMin(min, locMin);
|
||||||
|
max = qMax(max, locMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
const qreal sceneMin = m_barItem->mapFromFrameToScene(min);
|
||||||
|
|
||||||
|
QRectF barRect(sceneMin,
|
||||||
|
0,
|
||||||
|
(max - min) * m_barItem->rulerScaling(),
|
||||||
|
TimelineConstants::sectionHeight - 1);
|
||||||
|
|
||||||
|
m_barItem->setRect(barRect);
|
||||||
|
}
|
||||||
|
|
||||||
|
int TransitionEditorSectionItem::type() const
|
||||||
|
{
|
||||||
|
return Type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::updateData(QGraphicsItem *item)
|
||||||
|
{
|
||||||
|
if (auto sectionItem = qgraphicsitem_cast<TransitionEditorSectionItem *>(item))
|
||||||
|
sectionItem->updateData();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::invalidateBar(QGraphicsItem *item)
|
||||||
|
{
|
||||||
|
if (auto sectionItem = qgraphicsitem_cast<TransitionEditorSectionItem *>(item))
|
||||||
|
sectionItem->invalidateBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::updateDataForTarget(QGraphicsItem *item,
|
||||||
|
const ModelNode &target,
|
||||||
|
bool *b)
|
||||||
|
{
|
||||||
|
if (!target.isValid())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (auto sectionItem = qgraphicsitem_cast<TransitionEditorSectionItem *>(item)) {
|
||||||
|
if (sectionItem->m_targetNode == target) { //TODO update animation node
|
||||||
|
sectionItem->updateData();
|
||||||
|
if (b)
|
||||||
|
*b = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::moveAllDurations(qreal offset)
|
||||||
|
{
|
||||||
|
for (const ModelNode &sequential : m_animationNode.directSubModelNodes()) {
|
||||||
|
for (const ModelNode &child : sequential.directSubModelNodes()) {
|
||||||
|
if (child.hasMetaInfo() && child.isSubclassOf("QtQuick.PauseAnimation"))
|
||||||
|
moveDuration(child, offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::scaleAllDurations(qreal scale)
|
||||||
|
{
|
||||||
|
for (const ModelNode &sequential : m_animationNode.directSubModelNodes()) {
|
||||||
|
for (const ModelNode &child : sequential.directSubModelNodes()) {
|
||||||
|
if (child.hasMetaInfo() && child.isSubclassOf("QtQuick.PropertyAnimation"))
|
||||||
|
scaleDuration(child, scale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorSectionItem::firstFrame()
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
//if (!m_timeline.isValid())
|
||||||
|
//return 0;
|
||||||
|
|
||||||
|
//return m_timeline.minActualKeyframe(m_targetNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractView *TransitionEditorSectionItem::view() const
|
||||||
|
{
|
||||||
|
return m_animationNode.view();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorSectionItem::isSelected() const
|
||||||
|
{
|
||||||
|
return m_targetNode.isValid() && m_targetNode.isSelected();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode TransitionEditorSectionItem::targetNode() const
|
||||||
|
{
|
||||||
|
return m_targetNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QPixmap rotateby90(const QPixmap &pixmap)
|
||||||
|
{
|
||||||
|
QImage sourceImage = pixmap.toImage();
|
||||||
|
QImage destImage(pixmap.height(), pixmap.width(), sourceImage.format());
|
||||||
|
|
||||||
|
for (int x = 0; x < pixmap.width(); x++)
|
||||||
|
for (int y = 0; y < pixmap.height(); y++)
|
||||||
|
destImage.setPixel(y, x, sourceImage.pixel(x, y));
|
||||||
|
|
||||||
|
QPixmap result = QPixmap::fromImage(destImage);
|
||||||
|
|
||||||
|
result.setDevicePixelRatio(pixmap.devicePixelRatio());
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int devicePixelHeight(const QPixmap &pixmap)
|
||||||
|
{
|
||||||
|
return pixmap.height() / pixmap.devicePixelRatioF();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::paint(QPainter *painter,
|
||||||
|
const QStyleOptionGraphicsItem * /*option*/,
|
||||||
|
QWidget *)
|
||||||
|
{
|
||||||
|
if (m_targetNode.isValid()) {
|
||||||
|
painter->save();
|
||||||
|
|
||||||
|
const QColor textColor = Theme::getColor(Theme::PanelTextColorLight);
|
||||||
|
const QColor penColor = Theme::instance()->qmlDesignerBackgroundColorDarker();
|
||||||
|
QColor brushColor = Theme::getColor(Theme::BackgroundColorDark);
|
||||||
|
|
||||||
|
int fillOffset = 0;
|
||||||
|
if (isSelected()) {
|
||||||
|
brushColor = Theme::getColor(Theme::QmlDesigner_HighlightColor);
|
||||||
|
fillOffset = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->fillRect(0,
|
||||||
|
0,
|
||||||
|
TimelineConstants::sectionWidth,
|
||||||
|
TimelineConstants::sectionHeight - fillOffset,
|
||||||
|
brushColor);
|
||||||
|
painter->fillRect(TimelineConstants::sectionWidth,
|
||||||
|
0,
|
||||||
|
size().width() - TimelineConstants::sectionWidth,
|
||||||
|
size().height(),
|
||||||
|
Theme::instance()->qmlDesignerBackgroundColorDarkAlternate());
|
||||||
|
|
||||||
|
painter->setPen(penColor);
|
||||||
|
drawLine(painter,
|
||||||
|
TimelineConstants::sectionWidth - 1,
|
||||||
|
0,
|
||||||
|
TimelineConstants::sectionWidth - 1,
|
||||||
|
size().height() - 1);
|
||||||
|
drawLine(painter,
|
||||||
|
TimelineConstants::sectionWidth,
|
||||||
|
TimelineConstants::sectionHeight - 1,
|
||||||
|
size().width(),
|
||||||
|
TimelineConstants::sectionHeight - 1);
|
||||||
|
|
||||||
|
static const QPixmap arrow = Theme::getPixmap("down-arrow");
|
||||||
|
|
||||||
|
static const QPixmap arrow90 = rotateby90(arrow);
|
||||||
|
|
||||||
|
const QPixmap rotatedArrow = collapsed() ? arrow90 : arrow;
|
||||||
|
|
||||||
|
const int textOffset = QFontMetrics(font()).ascent()
|
||||||
|
+ (TimelineConstants::sectionHeight - QFontMetrics(font()).height())
|
||||||
|
/ 2;
|
||||||
|
|
||||||
|
painter->drawPixmap(collapsed() ? 6 : 4,
|
||||||
|
(TimelineConstants::sectionHeight - devicePixelHeight(rotatedArrow)) / 2,
|
||||||
|
rotatedArrow);
|
||||||
|
|
||||||
|
painter->setPen(textColor);
|
||||||
|
|
||||||
|
QFontMetrics fm(painter->font());
|
||||||
|
const QString elidedId = fm.elidedText(m_targetNode.id(),
|
||||||
|
Qt::ElideMiddle,
|
||||||
|
TimelineConstants::sectionWidth
|
||||||
|
- TimelineConstants::textIndentationSections);
|
||||||
|
painter->drawText(TimelineConstants::textIndentationSections, textOffset, elidedId);
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->pos().y() > TimelineConstants::sectionHeight
|
||||||
|
|| event->pos().x() < TimelineConstants::textIndentationSections) {
|
||||||
|
TimelineItem::mouseDoubleClickEvent(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->button() == Qt::LeftButton) {
|
||||||
|
event->accept();
|
||||||
|
toggleCollapsed();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->pos().y() > TimelineConstants::sectionHeight) {
|
||||||
|
TimelineItem::mousePressEvent(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->button() == Qt::LeftButton)
|
||||||
|
event->accept();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (event->pos().y() > TimelineConstants::sectionHeight) {
|
||||||
|
TimelineItem::mouseReleaseEvent(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event->button() != Qt::LeftButton)
|
||||||
|
return;
|
||||||
|
|
||||||
|
event->accept();
|
||||||
|
|
||||||
|
if (event->pos().x() > TimelineConstants::textIndentationSections
|
||||||
|
&& event->button() == Qt::LeftButton) {
|
||||||
|
if (m_targetNode.isValid())
|
||||||
|
m_targetNode.view()->setSelectedModelNode(m_targetNode);
|
||||||
|
} else {
|
||||||
|
toggleCollapsed();
|
||||||
|
}
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::resizeEvent(QGraphicsSceneResizeEvent *event)
|
||||||
|
{
|
||||||
|
TimelineItem::resizeEvent(event);
|
||||||
|
|
||||||
|
for (auto child : propertyItems()) {
|
||||||
|
TransitionEditorPropertyItem *item = static_cast<TransitionEditorPropertyItem *>(child);
|
||||||
|
item->resize(size().width(), TimelineConstants::sectionHeight);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *) {}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::updateData()
|
||||||
|
{
|
||||||
|
invalidateBar();
|
||||||
|
resize(rulerWidth(), size().height());
|
||||||
|
invalidateProperties();
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<QGraphicsItem *> TransitionEditorSectionItem::propertyItems() const
|
||||||
|
{
|
||||||
|
QList<QGraphicsItem *> list;
|
||||||
|
|
||||||
|
const QList<QGraphicsItem *> children = childItems();
|
||||||
|
for (auto child : children) {
|
||||||
|
if (m_barItem != child && m_dummyItem != child)
|
||||||
|
list.append(child);
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::invalidateHeight()
|
||||||
|
{
|
||||||
|
int height = 0;
|
||||||
|
bool visible = true;
|
||||||
|
|
||||||
|
if (collapsed()) {
|
||||||
|
height = TimelineConstants::sectionHeight;
|
||||||
|
visible = false;
|
||||||
|
} else {
|
||||||
|
const QList<ModelNode> propertyAnimations = m_animationNode.subModelNodesOfType(
|
||||||
|
"QtQuick.PropertyAnimation");
|
||||||
|
|
||||||
|
height = TimelineConstants::sectionHeight
|
||||||
|
+ propertyAnimations.count() * TimelineConstants::sectionHeight;
|
||||||
|
visible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto child : propertyItems())
|
||||||
|
child->setVisible(visible);
|
||||||
|
|
||||||
|
setPreferredHeight(height);
|
||||||
|
setMinimumHeight(height);
|
||||||
|
setMaximumHeight(height);
|
||||||
|
|
||||||
|
auto transitionScene = qobject_cast<TransitionEditorGraphicsScene *>(scene());
|
||||||
|
transitionScene->activateLayout();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::createPropertyItems()
|
||||||
|
{
|
||||||
|
int yPos = TimelineConstants::sectionHeight;
|
||||||
|
const QList<ModelNode> propertyAnimations = m_animationNode.subModelNodesOfType(
|
||||||
|
"QtQuick.PropertyAnimation");
|
||||||
|
for (const auto &anim : propertyAnimations) {
|
||||||
|
auto item = TransitionEditorPropertyItem::create(anim, this);
|
||||||
|
item->setY(yPos);
|
||||||
|
yPos = yPos + TimelineConstants::sectionHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::invalidateProperties()
|
||||||
|
{
|
||||||
|
for (auto child : propertyItems()) {
|
||||||
|
delete child;
|
||||||
|
}
|
||||||
|
|
||||||
|
createPropertyItems();
|
||||||
|
|
||||||
|
for (auto child : propertyItems()) {
|
||||||
|
TransitionEditorPropertyItem *item = static_cast<TransitionEditorPropertyItem *>(child);
|
||||||
|
item->updateData();
|
||||||
|
item->resize(size().width(), TimelineConstants::sectionHeight);
|
||||||
|
}
|
||||||
|
invalidateHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorSectionItem::collapsed() const
|
||||||
|
{
|
||||||
|
return m_targetNode.isValid() && !m_targetNode.hasAuxiliaryData("timeline_expanded");
|
||||||
|
}
|
||||||
|
|
||||||
|
qreal TransitionEditorSectionItem::rulerWidth() const
|
||||||
|
{
|
||||||
|
return static_cast<TimelineGraphicsScene *>(scene())->rulerWidth();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSectionItem::toggleCollapsed()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_targetNode.isValid(), return );
|
||||||
|
|
||||||
|
if (collapsed())
|
||||||
|
m_targetNode.setAuxiliaryData("timeline_expanded", true);
|
||||||
|
else
|
||||||
|
m_targetNode.removeAuxiliaryData("timeline_expanded");
|
||||||
|
|
||||||
|
invalidateHeight();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorBarItem::TransitionEditorBarItem(TransitionEditorSectionItem *parent)
|
||||||
|
: TimelineMovableAbstractItem(parent)
|
||||||
|
{
|
||||||
|
setAcceptHoverEvents(true);
|
||||||
|
setPen(Qt::NoPen);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorBarItem::TransitionEditorBarItem(TransitionEditorPropertyItem *parent)
|
||||||
|
: TimelineMovableAbstractItem(parent)
|
||||||
|
{
|
||||||
|
setAcceptHoverEvents(true);
|
||||||
|
setPen(Qt::NoPen);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::itemMoved(const QPointF &start, const QPointF &end)
|
||||||
|
{
|
||||||
|
if (isActiveHandle(Location::Undefined))
|
||||||
|
dragInit(rect(), start);
|
||||||
|
|
||||||
|
qreal min = qreal(TimelineConstants::sectionWidth + TimelineConstants::timelineLeftOffset
|
||||||
|
- scrollOffset());
|
||||||
|
qreal max = qreal(abstractScrollGraphicsScene()->rulerWidth() - TimelineConstants::sectionWidth
|
||||||
|
+ rect().width());
|
||||||
|
|
||||||
|
const qreal minFrameX = mapFromFrameToScene(abstractScrollGraphicsScene()->startFrame());
|
||||||
|
const qreal maxFrameX = mapFromFrameToScene(abstractScrollGraphicsScene()->endFrame());
|
||||||
|
|
||||||
|
if (min < minFrameX)
|
||||||
|
min = minFrameX;
|
||||||
|
|
||||||
|
if (max > maxFrameX)
|
||||||
|
max = maxFrameX;
|
||||||
|
|
||||||
|
if (isActiveHandle(Location::Center))
|
||||||
|
dragCenter(rect(), end, min, max);
|
||||||
|
else
|
||||||
|
dragHandle(rect(), end, min, max);
|
||||||
|
|
||||||
|
emit abstractScrollGraphicsScene()->statusBarMessageChanged(
|
||||||
|
tr("Range from %1 to %2")
|
||||||
|
.arg(qRound(mapFromSceneToFrame(rect().x())))
|
||||||
|
.arg(qRound(mapFromSceneToFrame(rect().width() + rect().x()))));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::commitPosition(const QPointF & /*point*/)
|
||||||
|
{
|
||||||
|
if (sectionItem() && sectionItem()->view()) {
|
||||||
|
if (m_handle != Location::Undefined) {
|
||||||
|
sectionItem()
|
||||||
|
->view()
|
||||||
|
->executeInTransaction("TransitionEditorBarItem::commitPosition", [this]() {
|
||||||
|
qreal scaleFactor = rect().width() / m_oldRect.width();
|
||||||
|
|
||||||
|
qreal moved = (rect().topLeft().x() - m_oldRect.topLeft().x()) / rulerScaling();
|
||||||
|
qreal supposedFirstFrame = qRound(moved);
|
||||||
|
|
||||||
|
sectionItem()->scaleAllDurations(scaleFactor);
|
||||||
|
sectionItem()->moveAllDurations(supposedFirstFrame);
|
||||||
|
sectionItem()->updateData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} else if (propertyItem() && propertyItem()->view()) {
|
||||||
|
if (m_handle != Location::Undefined) {
|
||||||
|
propertyItem()
|
||||||
|
->view()
|
||||||
|
->executeInTransaction("TransitionEditorBarItem::commitPosition", [this]() {
|
||||||
|
qreal scaleFactor = rect().width() / m_oldRect.width();
|
||||||
|
qreal moved = (rect().topLeft().x() - m_oldRect.topLeft().x()) / rulerScaling();
|
||||||
|
qreal supposedFirstFrame = qRound(moved);
|
||||||
|
scaleDuration(propertyItem()->propertyAnimation(), scaleFactor);
|
||||||
|
moveDuration(propertyItem()->pauseAnimation(), supposedFirstFrame);
|
||||||
|
propertyItem()->updateData();
|
||||||
|
propertyItem()->updateParentData();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
m_handle = Location::Undefined;
|
||||||
|
m_bounds = Location::Undefined;
|
||||||
|
m_pivot = 0.0;
|
||||||
|
m_oldRect = QRectF();
|
||||||
|
scrollOffsetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::scrollOffsetChanged()
|
||||||
|
{
|
||||||
|
if (sectionItem())
|
||||||
|
sectionItem()->invalidateBar();
|
||||||
|
else if (propertyItem())
|
||||||
|
propertyItem()->invalidateBar();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::paint(QPainter *painter,
|
||||||
|
const QStyleOptionGraphicsItem *option,
|
||||||
|
QWidget *widget)
|
||||||
|
{
|
||||||
|
Q_UNUSED(option)
|
||||||
|
Q_UNUSED(widget)
|
||||||
|
|
||||||
|
QColor brushColor = Theme::getColor(Theme::QmlDesigner_HighlightColor);
|
||||||
|
QColor brushColorSection = Theme::getColor(Theme::QmlDesigner_HighlightColor).darker(120);
|
||||||
|
QColor penColor = Theme::getColor(Theme::QmlDesigner_HighlightColor).lighter(140);
|
||||||
|
|
||||||
|
const QRectF itemRect = rect();
|
||||||
|
|
||||||
|
painter->save();
|
||||||
|
painter->setClipRect(TimelineConstants::sectionWidth,
|
||||||
|
0,
|
||||||
|
itemRect.width() + itemRect.x(),
|
||||||
|
itemRect.height());
|
||||||
|
|
||||||
|
if (sectionItem())
|
||||||
|
painter->fillRect(itemRect, brushColorSection);
|
||||||
|
else
|
||||||
|
painter->fillRect(itemRect, brushColor);
|
||||||
|
|
||||||
|
if (propertyItem() && propertyItem()->isSelected()) {
|
||||||
|
painter->setPen(penColor);
|
||||||
|
painter->drawRect(itemRect.adjusted(0, 0, 0, -1));
|
||||||
|
}
|
||||||
|
|
||||||
|
painter->restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event)
|
||||||
|
{
|
||||||
|
const auto p = event->pos();
|
||||||
|
|
||||||
|
QRectF left, right;
|
||||||
|
if (handleRects(rect(), left, right)) {
|
||||||
|
if (left.contains(p) || right.contains(p)) {
|
||||||
|
if (cursor().shape() != Qt::SizeHorCursor)
|
||||||
|
setCursor(QCursor(Qt::SizeHorCursor));
|
||||||
|
} else if (rect().contains(p)) {
|
||||||
|
if (cursor().shape() != Qt::ClosedHandCursor)
|
||||||
|
setCursor(QCursor(Qt::ClosedHandCursor));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rect().contains(p))
|
||||||
|
setCursor(QCursor(Qt::ClosedHandCursor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::contextMenuEvent(QGraphicsSceneContextMenuEvent * /*event*/) {}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::mousePressEvent(QGraphicsSceneMouseEvent * /*event*/)
|
||||||
|
{
|
||||||
|
if (propertyItem())
|
||||||
|
propertyItem()->select();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorSectionItem *TransitionEditorBarItem::sectionItem() const
|
||||||
|
{
|
||||||
|
return qgraphicsitem_cast<TransitionEditorSectionItem *>(parentItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorPropertyItem *TransitionEditorBarItem::propertyItem() const
|
||||||
|
{
|
||||||
|
return qgraphicsitem_cast<TransitionEditorPropertyItem *>(parentItem());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::dragInit(const QRectF &rect, const QPointF &pos)
|
||||||
|
{
|
||||||
|
QRectF left, right;
|
||||||
|
m_oldRect = rect;
|
||||||
|
if (handleRects(rect, left, right)) {
|
||||||
|
if (left.contains(pos)) {
|
||||||
|
m_handle = Location::Left;
|
||||||
|
m_pivot = pos.x() - left.topLeft().x();
|
||||||
|
} else if (right.contains(pos)) {
|
||||||
|
m_handle = Location::Right;
|
||||||
|
m_pivot = pos.x() - right.topRight().x();
|
||||||
|
} else if (rect.contains(pos)) {
|
||||||
|
m_handle = Location::Center;
|
||||||
|
m_pivot = pos.x() - rect.topLeft().x();
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
if (rect.contains(pos)) {
|
||||||
|
m_handle = Location::Center;
|
||||||
|
m_pivot = pos.x() - rect.topLeft().x();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::dragCenter(QRectF rect, const QPointF &pos, qreal min, qreal max)
|
||||||
|
{
|
||||||
|
if (validateBounds(pos.x() - rect.topLeft().x())) {
|
||||||
|
qreal targetX = pos.x() - m_pivot;
|
||||||
|
|
||||||
|
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { // snapping
|
||||||
|
qreal snappedTargetFrame = abstractScrollGraphicsScene()->snap(mapFromSceneToFrame(targetX));
|
||||||
|
targetX = mapFromFrameToScene(snappedTargetFrame);
|
||||||
|
}
|
||||||
|
rect.moveLeft(targetX);
|
||||||
|
if (rect.topLeft().x() < min) {
|
||||||
|
rect.moveLeft(min);
|
||||||
|
setOutOfBounds(Location::Left);
|
||||||
|
} else if (rect.topRight().x() > max) {
|
||||||
|
rect.moveRight(max);
|
||||||
|
setOutOfBounds(Location::Right);
|
||||||
|
}
|
||||||
|
setRect(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::dragHandle(QRectF rect, const QPointF &pos, qreal min, qreal max)
|
||||||
|
{
|
||||||
|
QRectF left, right;
|
||||||
|
handleRects(rect, left, right);
|
||||||
|
|
||||||
|
if (isActiveHandle(Location::Left)) {
|
||||||
|
if (validateBounds(pos.x() - left.topLeft().x())) {
|
||||||
|
qreal targetX = pos.x() - m_pivot;
|
||||||
|
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { // snapping
|
||||||
|
qreal snappedTargetFrame = abstractScrollGraphicsScene()->snap(mapFromSceneToFrame(targetX));
|
||||||
|
targetX = mapFromFrameToScene(snappedTargetFrame);
|
||||||
|
}
|
||||||
|
rect.setLeft(targetX);
|
||||||
|
if (rect.left() < min) {
|
||||||
|
rect.setLeft(min);
|
||||||
|
setOutOfBounds(Location::Left);
|
||||||
|
} else if (rect.left() >= rect.right() - minimumBarWidth)
|
||||||
|
rect.setLeft(rect.right() - minimumBarWidth);
|
||||||
|
|
||||||
|
setRect(rect);
|
||||||
|
}
|
||||||
|
} else if (isActiveHandle(Location::Right)) {
|
||||||
|
if (validateBounds(pos.x() - right.topRight().x())) {
|
||||||
|
qreal targetX = pos.x() - m_pivot;
|
||||||
|
if (QApplication::keyboardModifiers() & Qt::ShiftModifier) { // snapping
|
||||||
|
qreal snappedTargetFrame = abstractScrollGraphicsScene()->snap(mapFromSceneToFrame(targetX));
|
||||||
|
targetX = mapFromFrameToScene(snappedTargetFrame);
|
||||||
|
}
|
||||||
|
rect.setRight(targetX);
|
||||||
|
if (rect.right() > max) {
|
||||||
|
rect.setRight(max);
|
||||||
|
setOutOfBounds(Location::Right);
|
||||||
|
} else if (rect.right() <= rect.left() + minimumBarWidth)
|
||||||
|
rect.setRight(rect.left() + minimumBarWidth);
|
||||||
|
|
||||||
|
setRect(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorBarItem::handleRects(const QRectF &rect, QRectF &left, QRectF &right) const
|
||||||
|
{
|
||||||
|
if (rect.width() < minimumBarWidth)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const qreal handleSize = rect.height();
|
||||||
|
|
||||||
|
auto handleRect = QRectF(0, 0, handleSize, handleSize);
|
||||||
|
handleRect.moveCenter(rect.center());
|
||||||
|
|
||||||
|
handleRect.moveLeft(rect.left());
|
||||||
|
left = handleRect;
|
||||||
|
|
||||||
|
handleRect.moveRight(rect.right());
|
||||||
|
right = handleRect;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorBarItem::isActiveHandle(Location location) const
|
||||||
|
{
|
||||||
|
return m_handle == location;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorBarItem::setOutOfBounds(Location location)
|
||||||
|
{
|
||||||
|
m_bounds = location;
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorBarItem::validateBounds(qreal distance)
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
if (m_bounds == Location::Left) {
|
||||||
|
if (distance > m_pivot)
|
||||||
|
m_bounds = Location::Center;
|
||||||
|
return false;
|
||||||
|
|
||||||
|
} else if (m_bounds == Location::Right) {
|
||||||
|
if (distance < m_pivot)
|
||||||
|
m_bounds = Location::Center;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,145 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorconstants.h"
|
||||||
|
|
||||||
|
#include <timelineeditor/timelineitem.h>
|
||||||
|
#include <timelineeditor/timelinemovableabstractitem.h>
|
||||||
|
|
||||||
|
#include <modelnode.h>
|
||||||
|
#include <qmltimeline.h>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QComboBox)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QPainter)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TransitionEditorSectionItem;
|
||||||
|
class TransitionEditorPropertyItem;
|
||||||
|
|
||||||
|
class TransitionEditorBarItem : public TimelineMovableAbstractItem
|
||||||
|
{
|
||||||
|
Q_DECLARE_TR_FUNCTIONS(TimelineBarItem)
|
||||||
|
|
||||||
|
enum class Location { Undefined, Center, Left, Right };
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransitionEditorBarItem(TransitionEditorSectionItem *parent);
|
||||||
|
explicit TransitionEditorBarItem(TransitionEditorPropertyItem *parent);
|
||||||
|
|
||||||
|
void itemMoved(const QPointF &start, const QPointF &end) override;
|
||||||
|
void commitPosition(const QPointF &point) override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void scrollOffsetChanged() override;
|
||||||
|
void paint(QPainter *painter,
|
||||||
|
const QStyleOptionGraphicsItem *option,
|
||||||
|
QWidget *widget = nullptr) override;
|
||||||
|
void hoverMoveEvent(QGraphicsSceneHoverEvent *) override;
|
||||||
|
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
|
||||||
|
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TransitionEditorSectionItem *sectionItem() const;
|
||||||
|
TransitionEditorPropertyItem *propertyItem() const;
|
||||||
|
|
||||||
|
void dragInit(const QRectF &rect, const QPointF &pos);
|
||||||
|
void dragCenter(QRectF rect, const QPointF &pos, qreal min, qreal max);
|
||||||
|
void dragHandle(QRectF rect, const QPointF &pos, qreal min, qreal max);
|
||||||
|
bool handleRects(const QRectF &rect, QRectF &left, QRectF &right) const;
|
||||||
|
bool isActiveHandle(Location location) const;
|
||||||
|
|
||||||
|
void setOutOfBounds(Location location);
|
||||||
|
bool validateBounds(qreal pivot);
|
||||||
|
|
||||||
|
private:
|
||||||
|
Location m_handle = Location::Undefined;
|
||||||
|
|
||||||
|
Location m_bounds = Location::Undefined;
|
||||||
|
|
||||||
|
qreal m_pivot = 0.0;
|
||||||
|
|
||||||
|
QRectF m_oldRect;
|
||||||
|
|
||||||
|
static constexpr qreal minimumBarWidth = 2.0
|
||||||
|
* static_cast<qreal>(TimelineConstants::sectionHeight);
|
||||||
|
};
|
||||||
|
|
||||||
|
class TransitionEditorSectionItem : public TimelineItem
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
enum { Type = TransitionEditorConstants::transitionEditorSectionItemUserType };
|
||||||
|
|
||||||
|
static TransitionEditorSectionItem *create(const ModelNode &animation,
|
||||||
|
TimelineItem *parent);
|
||||||
|
|
||||||
|
void invalidateBar();
|
||||||
|
|
||||||
|
int type() const override;
|
||||||
|
|
||||||
|
static void updateData(QGraphicsItem *item);
|
||||||
|
static void invalidateBar(QGraphicsItem *item);
|
||||||
|
static void updateDataForTarget(QGraphicsItem *item, const ModelNode &target, bool *b);
|
||||||
|
|
||||||
|
void moveAllDurations(qreal offset);
|
||||||
|
void scaleAllDurations(qreal scale);
|
||||||
|
qreal firstFrame();
|
||||||
|
AbstractView *view() const;
|
||||||
|
bool isSelected() const;
|
||||||
|
|
||||||
|
ModelNode targetNode() const;
|
||||||
|
void updateData();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
|
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
void resizeEvent(QGraphicsSceneResizeEvent *event) override;
|
||||||
|
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void invalidateHeight();
|
||||||
|
void invalidateProperties();
|
||||||
|
bool collapsed() const;
|
||||||
|
qreal rulerWidth() const;
|
||||||
|
void toggleCollapsed();
|
||||||
|
void createPropertyItems();
|
||||||
|
const QList<QGraphicsItem *> propertyItems() const;
|
||||||
|
|
||||||
|
TransitionEditorSectionItem(TimelineItem *parent = nullptr);
|
||||||
|
ModelNode m_targetNode;
|
||||||
|
ModelNode m_animationNode;
|
||||||
|
|
||||||
|
TransitionEditorBarItem *m_barItem;
|
||||||
|
TimelineItem *m_dummyItem;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,177 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorsettingsdialog.h"
|
||||||
|
#include "timelinesettingsdialog.h"
|
||||||
|
#include "transitioneditorview.h"
|
||||||
|
#include "ui_transitioneditorsettingsdialog.h"
|
||||||
|
|
||||||
|
#include "timelineicons.h"
|
||||||
|
#include "timelinesettingsmodel.h"
|
||||||
|
#include "transitionform.h"
|
||||||
|
|
||||||
|
#include <abstractview.h>
|
||||||
|
#include <bindingproperty.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <nodelistproperty.h>
|
||||||
|
#include <nodemetainfo.h>
|
||||||
|
#include <rewritertransaction.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QKeyEvent>
|
||||||
|
#include <QToolBar>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
static void deleteAllTabs(QTabWidget *tabWidget)
|
||||||
|
{
|
||||||
|
while (tabWidget->count() > 0) {
|
||||||
|
QWidget *w = tabWidget->widget(0);
|
||||||
|
tabWidget->removeTab(0);
|
||||||
|
delete w;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ModelNode getTransitionFromTabWidget(QTabWidget *tabWidget)
|
||||||
|
{
|
||||||
|
QWidget *w = tabWidget->currentWidget();
|
||||||
|
if (w)
|
||||||
|
return qobject_cast<TransitionForm *>(w)->transition();
|
||||||
|
return QmlTimeline();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setTabForTransition(QTabWidget *tabWidget, const ModelNode &timeline)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tabWidget->count(); ++i) {
|
||||||
|
QWidget *w = tabWidget->widget(i);
|
||||||
|
if (qobject_cast<TransitionForm *>(w)->transition() == timeline) {
|
||||||
|
tabWidget->setCurrentIndex(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorSettingsDialog::TransitionEditorSettingsDialog(QWidget *parent,
|
||||||
|
class TransitionEditorView *view)
|
||||||
|
: QDialog(parent)
|
||||||
|
, ui(new Ui::TransitionEditorSettingsDialog)
|
||||||
|
, m_transitionEditorView(view)
|
||||||
|
{
|
||||||
|
//m_timelineSettingsModel = new TimelineSettingsModel(this, view);
|
||||||
|
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
auto *transitionCornerWidget = new QToolBar;
|
||||||
|
|
||||||
|
auto *transitionAddAction = new QAction(TimelineIcons::ADD_TIMELINE.icon(),
|
||||||
|
tr("Add Transition"));
|
||||||
|
auto *transitionRemoveAction = new QAction(TimelineIcons::REMOVE_TIMELINE.icon(),
|
||||||
|
tr("Remove Transition"));
|
||||||
|
|
||||||
|
connect(transitionAddAction, &QAction::triggered, this, [this]() {
|
||||||
|
setupTransitions(m_transitionEditorView->addNewTransition());
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(transitionRemoveAction, &QAction::triggered, this, [this]() {
|
||||||
|
ModelNode transition = getTransitionFromTabWidget(ui->timelineTab);
|
||||||
|
if (transition.isValid()) {
|
||||||
|
transition.destroy();
|
||||||
|
setupTransitions({});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
transitionCornerWidget->addAction(transitionAddAction);
|
||||||
|
transitionCornerWidget->addAction(transitionRemoveAction);
|
||||||
|
|
||||||
|
ui->timelineTab->setCornerWidget(transitionCornerWidget, Qt::TopRightCorner);
|
||||||
|
|
||||||
|
setupTransitions({});
|
||||||
|
|
||||||
|
connect(ui->timelineTab, &QTabWidget::currentChanged, this, [this]() {
|
||||||
|
m_currentTransition = getTransitionFromTabWidget(ui->timelineTab);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSettingsDialog::setCurrentTransition(const ModelNode &timeline)
|
||||||
|
{
|
||||||
|
m_currentTransition = timeline;
|
||||||
|
setTabForTransition(ui->timelineTab, m_currentTransition);
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorSettingsDialog::~TransitionEditorSettingsDialog()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSettingsDialog::keyPressEvent(QKeyEvent *event)
|
||||||
|
{
|
||||||
|
switch (event->key()) {
|
||||||
|
case Qt::Key_Return:
|
||||||
|
case Qt::Key_Enter:
|
||||||
|
/* ignore */
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
QDialog::keyPressEvent(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSettingsDialog::setupTransitions(const ModelNode &newTransition)
|
||||||
|
{
|
||||||
|
deleteAllTabs(ui->timelineTab);
|
||||||
|
|
||||||
|
const QList<ModelNode> &transitions = m_transitionEditorView->allTransitions();
|
||||||
|
|
||||||
|
if (transitions.isEmpty()) {
|
||||||
|
m_currentTransition = {};
|
||||||
|
auto transitionForm = new TransitionForm(this);
|
||||||
|
transitionForm->setDisabled(true);
|
||||||
|
ui->timelineTab->addTab(transitionForm, tr("No Transition"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &transition : transitions)
|
||||||
|
addTransitionTab(transition);
|
||||||
|
|
||||||
|
if (newTransition.isValid()) {
|
||||||
|
m_currentTransition = newTransition;
|
||||||
|
} else {
|
||||||
|
m_currentTransition = transitions.constFirst();
|
||||||
|
}
|
||||||
|
|
||||||
|
setTabForTransition(ui->timelineTab, m_currentTransition);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorSettingsDialog::addTransitionTab(const QmlTimeline &node)
|
||||||
|
{
|
||||||
|
auto transitionForm = new TransitionForm(this);
|
||||||
|
ui->timelineTab->addTab(transitionForm, node.modelNode().displayName());
|
||||||
|
transitionForm->setTransition(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,66 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <qmltimeline.h>
|
||||||
|
|
||||||
|
#include <QDialog>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QSpinBox)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TransitionForm;
|
||||||
|
class TransitionEditorView;
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class TransitionEditorSettingsDialog;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransitionEditorSettingsDialog : public QDialog
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransitionEditorSettingsDialog(QWidget *parent, class TransitionEditorView *view);
|
||||||
|
void setCurrentTransition(const ModelNode &timeline);
|
||||||
|
~TransitionEditorSettingsDialog() override;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupTransitions(const ModelNode &node);
|
||||||
|
|
||||||
|
void addTransitionTab(const QmlTimeline &node);
|
||||||
|
|
||||||
|
Ui::TransitionEditorSettingsDialog *ui;
|
||||||
|
|
||||||
|
TransitionEditorView *m_transitionEditorView;
|
||||||
|
ModelNode m_currentTransition;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,74 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>QmlDesigner::TransitionEditorSettingsDialog</class>
|
||||||
|
<widget class="QDialog" name="QmlDesigner::TransitionEditorSettingsDialog">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>519</width>
|
||||||
|
<height>582</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<property name="windowTitle">
|
||||||
|
<string>Transition Settings</string>
|
||||||
|
</property>
|
||||||
|
<property name="modal">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<widget class="QTabWidget" name="timelineTab">
|
||||||
|
<property name="currentIndex">
|
||||||
|
<number>-1</number>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="standardButtons">
|
||||||
|
<set>QDialogButtonBox::Close</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>accepted()</signal>
|
||||||
|
<receiver>QmlDesigner::TransitionEditorSettingsDialog</receiver>
|
||||||
|
<slot>accept()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>248</x>
|
||||||
|
<y>254</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>157</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
<connection>
|
||||||
|
<sender>buttonBox</sender>
|
||||||
|
<signal>rejected()</signal>
|
||||||
|
<receiver>QmlDesigner::TransitionEditorSettingsDialog</receiver>
|
||||||
|
<slot>reject()</slot>
|
||||||
|
<hints>
|
||||||
|
<hint type="sourcelabel">
|
||||||
|
<x>316</x>
|
||||||
|
<y>260</y>
|
||||||
|
</hint>
|
||||||
|
<hint type="destinationlabel">
|
||||||
|
<x>286</x>
|
||||||
|
<y>274</y>
|
||||||
|
</hint>
|
||||||
|
</hints>
|
||||||
|
</connection>
|
||||||
|
</connections>
|
||||||
|
</ui>
|
@@ -0,0 +1,342 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditortoolbar.h"
|
||||||
|
#include "transitioneditorgraphicsscene.h"
|
||||||
|
|
||||||
|
#include "timelineconstants.h"
|
||||||
|
|
||||||
|
#include "timelineicons.h"
|
||||||
|
|
||||||
|
#include "timelineview.h"
|
||||||
|
#include "timelinewidget.h"
|
||||||
|
|
||||||
|
#include <designeractionmanager.h>
|
||||||
|
#include <nodelistproperty.h>
|
||||||
|
#include <theme.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
#include <qmlstate.h>
|
||||||
|
#include <qmltimeline.h>
|
||||||
|
|
||||||
|
#include <coreplugin/actionmanager/actionmanager.h>
|
||||||
|
#include <coreplugin/actionmanager/command.h>
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QIntValidator>
|
||||||
|
#include <QLineEdit>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QSlider>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
static bool isSpacer(QObject *object)
|
||||||
|
{
|
||||||
|
return object->property("spacer_widget").toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
static QWidget *createSpacer()
|
||||||
|
{
|
||||||
|
QWidget *spacer = new QWidget();
|
||||||
|
spacer->setProperty("spacer_widget", true);
|
||||||
|
return spacer;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int controlWidth(QToolBar *bar, QObject *control)
|
||||||
|
{
|
||||||
|
QWidget *widget = nullptr;
|
||||||
|
|
||||||
|
if (auto *action = qobject_cast<QAction *>(control))
|
||||||
|
widget = bar->widgetForAction(action);
|
||||||
|
|
||||||
|
if (widget == nullptr)
|
||||||
|
widget = qobject_cast<QWidget *>(control);
|
||||||
|
|
||||||
|
if (widget)
|
||||||
|
return widget->width();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static QAction *createAction(const Core::Id &id,
|
||||||
|
const QIcon &icon,
|
||||||
|
const QString &name,
|
||||||
|
const QKeySequence &shortcut)
|
||||||
|
{
|
||||||
|
QString text = QString("%1 (%2)").arg(name).arg(shortcut.toString());
|
||||||
|
|
||||||
|
Core::Context context(TimelineConstants::C_QMLTIMELINE);
|
||||||
|
|
||||||
|
auto *action = new QAction(icon, text);
|
||||||
|
auto *command = Core::ActionManager::registerAction(action, id, context);
|
||||||
|
command->setDefaultKeySequence(shortcut);
|
||||||
|
|
||||||
|
return action;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorToolBar::TransitionEditorToolBar(QWidget *parent)
|
||||||
|
: QToolBar(parent)
|
||||||
|
, m_grp()
|
||||||
|
{
|
||||||
|
setContentsMargins(0, 0, 0, 0);
|
||||||
|
createLeftControls();
|
||||||
|
createCenterControls();
|
||||||
|
createRightControls();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::reset() {}
|
||||||
|
|
||||||
|
int TransitionEditorToolBar::scaleFactor() const
|
||||||
|
{
|
||||||
|
if (m_scale)
|
||||||
|
return m_scale->value();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString TransitionEditorToolBar::currentTransitionId() const
|
||||||
|
{
|
||||||
|
return m_transitionComboBox->currentText();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::setBlockReflection(bool block)
|
||||||
|
{
|
||||||
|
m_blockReflection = block;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::updateComboBox(const ModelNode &root)
|
||||||
|
{
|
||||||
|
if (root.isValid() && root.hasProperty("transitions")) {
|
||||||
|
NodeAbstractProperty transitions = root.nodeAbstractProperty("transitions");
|
||||||
|
if (transitions.isValid())
|
||||||
|
for (const ModelNode &transition : transitions.directSubNodes())
|
||||||
|
m_transitionComboBox->addItem(transition.id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::setCurrentTransition(const ModelNode &transition)
|
||||||
|
{
|
||||||
|
if (m_blockReflection)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (transition.isValid()) {
|
||||||
|
m_transitionComboBox->clear();
|
||||||
|
const ModelNode root = transition.view()->rootModelNode();
|
||||||
|
updateComboBox(root);
|
||||||
|
m_transitionComboBox->setCurrentText(transition.id());
|
||||||
|
} else {
|
||||||
|
m_transitionComboBox->clear();
|
||||||
|
m_transitionComboBox->setCurrentText("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::setDuration(qreal frame)
|
||||||
|
{
|
||||||
|
auto text = QString::number(frame, 'f', 0);
|
||||||
|
m_duration->setText(text);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::setScaleFactor(int factor)
|
||||||
|
{
|
||||||
|
const QSignalBlocker blocker(m_scale);
|
||||||
|
m_scale->setValue(factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::setActionEnabled(const QString &name, bool enabled)
|
||||||
|
{
|
||||||
|
for (auto *action : actions())
|
||||||
|
if (action->objectName() == name)
|
||||||
|
action->setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::createLeftControls()
|
||||||
|
{
|
||||||
|
auto addActionToGroup = [&](QAction *action) {
|
||||||
|
addAction(action);
|
||||||
|
m_grp << action;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto addWidgetToGroup = [&](QWidget *widget) {
|
||||||
|
addWidget(widget);
|
||||||
|
m_grp << widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto addSpacingToGroup = [&](int width) {
|
||||||
|
auto *widget = new QWidget;
|
||||||
|
widget->setFixedWidth(width);
|
||||||
|
addWidget(widget);
|
||||||
|
m_grp << widget;
|
||||||
|
};
|
||||||
|
|
||||||
|
addSpacingToGroup(5);
|
||||||
|
|
||||||
|
auto *settingsAction = createAction(TimelineConstants::C_SETTINGS,
|
||||||
|
TimelineIcons::ANIMATION.icon(),
|
||||||
|
tr("Transition Settings"),
|
||||||
|
QKeySequence(Qt::Key_S));
|
||||||
|
connect(settingsAction,
|
||||||
|
&QAction::triggered,
|
||||||
|
this,
|
||||||
|
&TransitionEditorToolBar::settingDialogClicked);
|
||||||
|
|
||||||
|
addActionToGroup(settingsAction);
|
||||||
|
|
||||||
|
addWidgetToGroup(createSpacer());
|
||||||
|
|
||||||
|
m_transitionComboBox = new QComboBox(this);
|
||||||
|
addWidgetToGroup(m_transitionComboBox);
|
||||||
|
|
||||||
|
connect(m_transitionComboBox, &QComboBox::currentTextChanged, this, [this]() {
|
||||||
|
emit currentTransitionChanged(m_transitionComboBox->currentText());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
static QLineEdit *createToolBarLineEdit(QWidget *parent)
|
||||||
|
{
|
||||||
|
auto lineEdit = new QLineEdit(parent);
|
||||||
|
lineEdit->setStyleSheet("* { background-color: rgba(0, 0, 0, 0); }");
|
||||||
|
lineEdit->setFixedWidth(48);
|
||||||
|
lineEdit->setAlignment(Qt::AlignCenter);
|
||||||
|
|
||||||
|
QPalette pal = parent->palette();
|
||||||
|
pal.setColor(QPalette::Text, Theme::instance()->color(Utils::Theme::PanelTextColorLight));
|
||||||
|
lineEdit->setPalette(pal);
|
||||||
|
QValidator *validator = new QIntValidator(-100000, 100000, lineEdit);
|
||||||
|
lineEdit->setValidator(validator);
|
||||||
|
|
||||||
|
return lineEdit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::createCenterControls()
|
||||||
|
{
|
||||||
|
addSpacing(10);
|
||||||
|
|
||||||
|
auto *curvePicker = createAction(TimelineConstants::C_CURVE_PICKER,
|
||||||
|
TimelineIcons::CURVE_EDITOR.icon(),
|
||||||
|
tr("Easing Curve Editor"),
|
||||||
|
QKeySequence(Qt::Key_C));
|
||||||
|
|
||||||
|
curvePicker->setObjectName("Easing Curve Editor");
|
||||||
|
connect(curvePicker, &QAction::triggered, this, &TransitionEditorToolBar::openEasingCurveEditor);
|
||||||
|
addAction(curvePicker);
|
||||||
|
|
||||||
|
addSpacing(10);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
addSeparator();
|
||||||
|
|
||||||
|
addSpacing(10);
|
||||||
|
|
||||||
|
auto *curveEditor = new QAction(TimelineIcons::CURVE_PICKER.icon(), tr("Curve Editor"));
|
||||||
|
addAction(curveEditor);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::createRightControls()
|
||||||
|
{
|
||||||
|
auto *spacer = createSpacer();
|
||||||
|
spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||||
|
addWidget(spacer);
|
||||||
|
|
||||||
|
addSeparator();
|
||||||
|
addSpacing(10);
|
||||||
|
|
||||||
|
auto *zoomOut = createAction(TimelineConstants::C_ZOOM_OUT,
|
||||||
|
TimelineIcons::ZOOM_SMALL.icon(),
|
||||||
|
tr("Zoom Out"),
|
||||||
|
QKeySequence(QKeySequence::ZoomOut));
|
||||||
|
|
||||||
|
connect(zoomOut, &QAction::triggered, [this]() {
|
||||||
|
m_scale->setValue(m_scale->value() - m_scale->pageStep());
|
||||||
|
});
|
||||||
|
addAction(zoomOut);
|
||||||
|
|
||||||
|
addSpacing(10);
|
||||||
|
|
||||||
|
m_scale = new QSlider(this);
|
||||||
|
m_scale->setOrientation(Qt::Horizontal);
|
||||||
|
m_scale->setMaximumWidth(200);
|
||||||
|
m_scale->setMinimumWidth(100);
|
||||||
|
m_scale->setMinimum(0);
|
||||||
|
m_scale->setMaximum(100);
|
||||||
|
m_scale->setValue(0);
|
||||||
|
|
||||||
|
connect(m_scale, &QSlider::valueChanged, this, &TransitionEditorToolBar::scaleFactorChanged);
|
||||||
|
addWidget(m_scale);
|
||||||
|
|
||||||
|
addSpacing(10);
|
||||||
|
|
||||||
|
auto *zoomIn = createAction(TimelineConstants::C_ZOOM_IN,
|
||||||
|
TimelineIcons::ZOOM_BIG.icon(),
|
||||||
|
tr("Zoom In"),
|
||||||
|
QKeySequence(QKeySequence::ZoomIn));
|
||||||
|
|
||||||
|
connect(zoomIn, &QAction::triggered, [this]() {
|
||||||
|
m_scale->setValue(m_scale->value() + m_scale->pageStep());
|
||||||
|
});
|
||||||
|
addAction(zoomIn);
|
||||||
|
|
||||||
|
addSpacing(10);
|
||||||
|
|
||||||
|
addSeparator();
|
||||||
|
|
||||||
|
m_duration = createToolBarLineEdit(this);
|
||||||
|
addWidget(m_duration);
|
||||||
|
|
||||||
|
auto emitEndChanged = [this]() { emit durationChanged(m_duration->text().toInt()); };
|
||||||
|
connect(m_duration, &QLineEdit::editingFinished, emitEndChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::addSpacing(int width)
|
||||||
|
{
|
||||||
|
auto *widget = new QWidget;
|
||||||
|
widget->setFixedWidth(width);
|
||||||
|
addWidget(widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorToolBar::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event)
|
||||||
|
|
||||||
|
int width = 0;
|
||||||
|
QWidget *spacer = nullptr;
|
||||||
|
for (auto *object : qAsConst(m_grp)) {
|
||||||
|
if (isSpacer(object))
|
||||||
|
spacer = qobject_cast<QWidget *>(object);
|
||||||
|
else
|
||||||
|
width += controlWidth(this, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (spacer) {
|
||||||
|
int spacerWidth = TimelineConstants::sectionWidth - width - 12;
|
||||||
|
spacer->setFixedWidth(spacerWidth > 0 ? spacerWidth : 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,92 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "animationcurvedialog.h"
|
||||||
|
#include "animationcurveeditormodel.h"
|
||||||
|
|
||||||
|
#include <QToolBar>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QComboBox)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QLineEdit)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QObject)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QResizeEvent)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QSlider)
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QWidget)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TimelineWidget;
|
||||||
|
|
||||||
|
class QmlTimeline;
|
||||||
|
|
||||||
|
class TransitionEditorToolBar : public QToolBar
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void settingDialogClicked();
|
||||||
|
|
||||||
|
void scaleFactorChanged(int value);
|
||||||
|
void durationChanged(int value);
|
||||||
|
void currentTransitionChanged(const QString &name);
|
||||||
|
void openEasingCurveEditor();
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransitionEditorToolBar(QWidget *parent = nullptr);
|
||||||
|
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
int scaleFactor() const;
|
||||||
|
QString currentTransitionId() const;
|
||||||
|
|
||||||
|
void setBlockReflection(bool block);
|
||||||
|
void setCurrentTransition(const ModelNode &transition);
|
||||||
|
void setDuration(qreal frame);
|
||||||
|
void setScaleFactor(int factor);
|
||||||
|
|
||||||
|
void setActionEnabled(const QString &name, bool enabled);
|
||||||
|
|
||||||
|
void updateComboBox(const ModelNode &root);
|
||||||
|
protected:
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void createLeftControls();
|
||||||
|
void createCenterControls();
|
||||||
|
void createRightControls();
|
||||||
|
void addSpacing(int width);
|
||||||
|
|
||||||
|
QList<QObject *> m_grp;
|
||||||
|
|
||||||
|
QComboBox *m_transitionComboBox = nullptr;
|
||||||
|
QSlider *m_scale = nullptr;
|
||||||
|
QLineEdit *m_duration = nullptr;
|
||||||
|
|
||||||
|
bool m_blockReflection = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,348 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorview.h"
|
||||||
|
|
||||||
|
#include "transitioneditortoolbar.h"
|
||||||
|
#include "transitioneditorwidget.h"
|
||||||
|
|
||||||
|
#include "transitioneditorgraphicsscene.h"
|
||||||
|
#include "transitioneditorsettingsdialog.h"
|
||||||
|
|
||||||
|
#include <bindingproperty.h>
|
||||||
|
#include <exception.h>
|
||||||
|
#include <modelnodecontextmenu_helper.h>
|
||||||
|
#include <nodeabstractproperty.h>
|
||||||
|
#include <nodelistproperty.h>
|
||||||
|
#include <nodemetainfo.h>
|
||||||
|
#include <rewritertransaction.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
#include <viewmanager.h>
|
||||||
|
#include <qmldesignericons.h>
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <qmlitemnode.h>
|
||||||
|
#include <qmlobjectnode.h>
|
||||||
|
#include <qmlstate.h>
|
||||||
|
#include <qmltimeline.h>
|
||||||
|
#include <qmltimelinekeyframegroup.h>
|
||||||
|
|
||||||
|
#include <designmodecontext.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
#include <coreplugin/messagebox.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
TransitionEditorView::TransitionEditorView(QObject *parent)
|
||||||
|
: AbstractView(parent)
|
||||||
|
, m_transitionEditorWidget(nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorView::~TransitionEditorView() = default;
|
||||||
|
|
||||||
|
void TransitionEditorView::modelAttached(Model *model)
|
||||||
|
{
|
||||||
|
AbstractView::modelAttached(model);
|
||||||
|
if (m_transitionEditorWidget)
|
||||||
|
m_transitionEditorWidget->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::modelAboutToBeDetached(Model *model)
|
||||||
|
{
|
||||||
|
m_transitionEditorWidget->reset();
|
||||||
|
|
||||||
|
AbstractView::modelAboutToBeDetached(model);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::nodeCreated(const ModelNode & /*createdNode*/) {}
|
||||||
|
|
||||||
|
void TransitionEditorView::nodeAboutToBeRemoved(const ModelNode & /*removedNode*/) {}
|
||||||
|
|
||||||
|
void TransitionEditorView::nodeRemoved(const ModelNode & removedNode,
|
||||||
|
const NodeAbstractProperty &parentProperty,
|
||||||
|
PropertyChangeFlags /*propertyChange*/)
|
||||||
|
{
|
||||||
|
if (parentProperty.name() == "transitions")
|
||||||
|
widget()->updateData(removedNode);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::nodeReparented(const ModelNode &node,
|
||||||
|
const NodeAbstractProperty &newPropertyParent,
|
||||||
|
const NodeAbstractProperty & /*oldPropertyParent*/,
|
||||||
|
AbstractView::PropertyChangeFlags /*propertyChange*/)
|
||||||
|
{
|
||||||
|
if (newPropertyParent.name() == "transitions")
|
||||||
|
asyncUpdate(node);
|
||||||
|
|
||||||
|
const ModelNode parent = newPropertyParent.parentModelNode();
|
||||||
|
|
||||||
|
qDebug() << Q_FUNC_INFO << parent;
|
||||||
|
if (parent.isValid() && parent.metaInfo().isValid()
|
||||||
|
&& parent.metaInfo().isSubclassOf("QtQuick.Transition")) {
|
||||||
|
asyncUpdate(parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::instancePropertyChanged(
|
||||||
|
const QList<QPair<ModelNode, PropertyName>> & /*propertyList*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::variantPropertiesChanged(
|
||||||
|
const QList<VariantProperty> & /* propertyList */,
|
||||||
|
AbstractView::PropertyChangeFlags /*propertyChange*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::bindingPropertiesChanged(
|
||||||
|
const QList<BindingProperty> & /*propertyList */,
|
||||||
|
AbstractView::PropertyChangeFlags /* propertyChange */)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::selectedNodesChanged(const QList<ModelNode> & /*selectedNodeList*/,
|
||||||
|
const QList<ModelNode> & /*lastSelectedNodeList*/)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::propertiesAboutToBeRemoved(
|
||||||
|
const QList<AbstractProperty> & /*propertyList */)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::propertiesRemoved(const QList<AbstractProperty> &propertyList)
|
||||||
|
{
|
||||||
|
for (const AbstractProperty &property : propertyList) {
|
||||||
|
if (property.name() == "transitions")
|
||||||
|
widget()->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TransitionEditorView::hasWidget() const
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::nodeIdChanged(const ModelNode &node, const QString &, const QString &)
|
||||||
|
{
|
||||||
|
if (node.metaInfo().isValid() && node.metaInfo().isSubclassOf("QtQuick.Transition"))
|
||||||
|
widget()->init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::currentStateChanged(const ModelNode &)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorWidget *TransitionEditorView::widget() const
|
||||||
|
{
|
||||||
|
return m_transitionEditorWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::registerActions()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode TransitionEditorView::addNewTransition()
|
||||||
|
{
|
||||||
|
QList<QmlModelState> states;
|
||||||
|
const ModelNode root = rootModelNode();
|
||||||
|
|
||||||
|
if (QmlVisualNode::isValidQmlVisualNode(root)) {
|
||||||
|
states = QmlVisualNode(root).states().allStates();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (states.isEmpty()) {
|
||||||
|
Core::AsynchronousMessageBox::warning(tr("No States Defined"),
|
||||||
|
tr("There are no states defined in this component."));
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QHash<QString, QStringList> idPropertyList;
|
||||||
|
|
||||||
|
const QVector<TypeName> validProperties = {"int", "real", "double", "qreal", "color", "QColor"};
|
||||||
|
|
||||||
|
for (const QmlModelState &state : qAsConst(states)) {
|
||||||
|
for (const QmlPropertyChanges & change : state.propertyChanges()) {
|
||||||
|
QStringList locList;
|
||||||
|
const ModelNode target = change.target();
|
||||||
|
const QString targetId = target.id();
|
||||||
|
if (target.isValid() && target.hasMetaInfo()) {
|
||||||
|
for (const VariantProperty &property : change.modelNode().variantProperties()) {
|
||||||
|
TypeName typeName = target.metaInfo().propertyTypeName(property.name());
|
||||||
|
|
||||||
|
if (validProperties.contains(typeName))
|
||||||
|
locList.append(QString::fromUtf8(property.name()));
|
||||||
|
}
|
||||||
|
if (idPropertyList.contains(targetId)) {
|
||||||
|
QStringList newlist = idPropertyList.value(targetId);
|
||||||
|
for (const QString &str :locList)
|
||||||
|
if (!newlist.contains(str))
|
||||||
|
newlist.append(str);
|
||||||
|
idPropertyList.insert(targetId, newlist);
|
||||||
|
} else {
|
||||||
|
if (!locList.isEmpty())
|
||||||
|
idPropertyList.insert(targetId, locList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode transition;
|
||||||
|
|
||||||
|
if (!idPropertyList.isEmpty()) {
|
||||||
|
executeInTransaction(
|
||||||
|
" TransitionEditorView::addNewTransition", [&transition, idPropertyList, root, this]() {
|
||||||
|
transition = createModelNode("QtQuick.Transition",
|
||||||
|
2,
|
||||||
|
0,
|
||||||
|
{{
|
||||||
|
"from",
|
||||||
|
"*",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"to",
|
||||||
|
"*",
|
||||||
|
}});
|
||||||
|
transition.setAuxiliaryData("transitionDuration", 2000);
|
||||||
|
transition.validId();
|
||||||
|
root.nodeListProperty("transitions").reparentHere(transition);
|
||||||
|
|
||||||
|
for (const QString &id : idPropertyList.keys()) {
|
||||||
|
ModelNode parallelAnimation = createModelNode("QtQuick.ParallelAnimation",
|
||||||
|
2,
|
||||||
|
12);
|
||||||
|
transition.defaultNodeAbstractProperty().reparentHere(parallelAnimation);
|
||||||
|
for (const QString &property : idPropertyList.value(id)) {
|
||||||
|
ModelNode sequentialAnimation
|
||||||
|
= createModelNode("QtQuick.SequentialAnimation", 2, 12);
|
||||||
|
parallelAnimation.defaultNodeAbstractProperty().reparentHere(
|
||||||
|
sequentialAnimation);
|
||||||
|
|
||||||
|
ModelNode pauseAnimation = createModelNode("QtQuick.PauseAnimation",
|
||||||
|
2,
|
||||||
|
12,
|
||||||
|
{{"duration", 50}});
|
||||||
|
sequentialAnimation.defaultNodeAbstractProperty().reparentHere(
|
||||||
|
pauseAnimation);
|
||||||
|
|
||||||
|
ModelNode propertyAnimation = createModelNode("QtQuick.PropertyAnimation",
|
||||||
|
2,
|
||||||
|
12,
|
||||||
|
{{"property", property},
|
||||||
|
{"duration", 150}});
|
||||||
|
propertyAnimation.bindingProperty("target").setExpression(id);
|
||||||
|
sequentialAnimation.defaultNodeAbstractProperty().reparentHere(
|
||||||
|
propertyAnimation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_transitionEditorWidget)
|
||||||
|
m_transitionEditorWidget->init();
|
||||||
|
|
||||||
|
return transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorWidget *TransitionEditorView::createWidget()
|
||||||
|
{
|
||||||
|
if (!m_transitionEditorWidget)
|
||||||
|
m_transitionEditorWidget = new TransitionEditorWidget(this);
|
||||||
|
|
||||||
|
//auto *timelineContext = new TimelineContext(m_timelineWidget);
|
||||||
|
//Core::ICore::addContextObject(timelineContext);
|
||||||
|
|
||||||
|
return m_transitionEditorWidget;
|
||||||
|
}
|
||||||
|
|
||||||
|
WidgetInfo TransitionEditorView::widgetInfo()
|
||||||
|
{
|
||||||
|
return createWidgetInfo(createWidget(),
|
||||||
|
nullptr,
|
||||||
|
"TransitionEditor",
|
||||||
|
WidgetInfo::BottomPane,
|
||||||
|
0,
|
||||||
|
tr("Transition Editor"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::openSettingsDialog()
|
||||||
|
{
|
||||||
|
auto dialog = new TransitionEditorSettingsDialog(Core::ICore::dialogParent(), this);
|
||||||
|
|
||||||
|
auto transition = widget()->graphicsScene()->transitionModelNode();
|
||||||
|
if (transition.isValid())
|
||||||
|
dialog->setCurrentTransition(transition);
|
||||||
|
|
||||||
|
QObject::connect(dialog, &TransitionEditorSettingsDialog::rejected, [this, dialog]() {
|
||||||
|
widget()->init();
|
||||||
|
dialog->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
QObject::connect(dialog, &TransitionEditorSettingsDialog::accepted, [this, dialog]() {
|
||||||
|
widget()->init();
|
||||||
|
dialog->deleteLater();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->show();
|
||||||
|
}
|
||||||
|
|
||||||
|
const QList<ModelNode> TransitionEditorView::allTransitions() const
|
||||||
|
{
|
||||||
|
if (rootModelNode().isValid() && rootModelNode().hasProperty("transitions")) {
|
||||||
|
NodeAbstractProperty transitions = rootModelNode().nodeAbstractProperty("transitions");
|
||||||
|
if (transitions.isValid())
|
||||||
|
return transitions.directSubNodes();
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorView::asyncUpdate(const ModelNode &transition)
|
||||||
|
{
|
||||||
|
static bool updateTriggered = false;
|
||||||
|
|
||||||
|
if (!updateTriggered && (transition.id() == widget()->toolBar()->currentTransitionId())) {
|
||||||
|
updateTriggered = true;
|
||||||
|
QTimer::singleShot(0, [this, transition]() {
|
||||||
|
widget()->updateData(transition);
|
||||||
|
updateTriggered = false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,97 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "animationcurvedialog.h"
|
||||||
|
#include "animationcurveeditormodel.h"
|
||||||
|
#include "treeitem.h"
|
||||||
|
|
||||||
|
#include <abstractview.h>
|
||||||
|
|
||||||
|
#include <QPointer>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TransitionEditorWidget;
|
||||||
|
|
||||||
|
class TransitionEditorView : public AbstractView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransitionEditorView(QObject *parent = nullptr);
|
||||||
|
~TransitionEditorView() override;
|
||||||
|
//Abstract View
|
||||||
|
WidgetInfo widgetInfo() override;
|
||||||
|
void modelAttached(Model *model) override;
|
||||||
|
void modelAboutToBeDetached(Model *model) override;
|
||||||
|
void nodeCreated(const ModelNode &createdNode) override;
|
||||||
|
void nodeAboutToBeRemoved(const ModelNode &removedNode) override;
|
||||||
|
void nodeRemoved(const ModelNode &removedNode,
|
||||||
|
const NodeAbstractProperty &parentProperty,
|
||||||
|
PropertyChangeFlags propertyChange) override;
|
||||||
|
void nodeReparented(const ModelNode &node,
|
||||||
|
const NodeAbstractProperty &newPropertyParent,
|
||||||
|
const NodeAbstractProperty &oldPropertyParent,
|
||||||
|
PropertyChangeFlags propertyChange) override;
|
||||||
|
void instancePropertyChanged(const QList<QPair<ModelNode, PropertyName>> &propertyList) override;
|
||||||
|
void variantPropertiesChanged(const QList<VariantProperty> &propertyList,
|
||||||
|
PropertyChangeFlags propertyChange) override;
|
||||||
|
void bindingPropertiesChanged(const QList<BindingProperty> &propertyList,
|
||||||
|
PropertyChangeFlags propertyChange) override;
|
||||||
|
void selectedNodesChanged(const QList<ModelNode> &selectedNodeList,
|
||||||
|
const QList<ModelNode> &lastSelectedNodeList) override;
|
||||||
|
|
||||||
|
void propertiesAboutToBeRemoved(const QList<AbstractProperty> &propertyList) override;
|
||||||
|
void propertiesRemoved(const QList<AbstractProperty> &propertyList) override;
|
||||||
|
|
||||||
|
bool hasWidget() const override;
|
||||||
|
|
||||||
|
void nodeIdChanged(const ModelNode &node, const QString &, const QString &) override;
|
||||||
|
|
||||||
|
void currentStateChanged(const ModelNode &node) override;
|
||||||
|
|
||||||
|
TransitionEditorWidget *widget() const;
|
||||||
|
|
||||||
|
void insertKeyframe(const ModelNode &target, const PropertyName &propertyName);
|
||||||
|
|
||||||
|
void registerActions();
|
||||||
|
|
||||||
|
ModelNode addNewTransition();
|
||||||
|
|
||||||
|
void openSettingsDialog();
|
||||||
|
|
||||||
|
const QList<ModelNode> allTransitions() const;
|
||||||
|
|
||||||
|
void asyncUpdate(const ModelNode &transition);
|
||||||
|
|
||||||
|
private:
|
||||||
|
TransitionEditorWidget *createWidget();
|
||||||
|
|
||||||
|
TransitionEditorWidget *m_transitionEditorWidget = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,414 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitioneditorwidget.h"
|
||||||
|
|
||||||
|
#include "transitioneditorgraphicsscene.h"
|
||||||
|
#include "transitioneditorpropertyitem.h"
|
||||||
|
#include "transitioneditortoolbar.h"
|
||||||
|
#include "transitioneditorview.h"
|
||||||
|
|
||||||
|
#include <timelineeditor/easingcurvedialog.h>
|
||||||
|
#include <timelineeditor/timelineconstants.h>
|
||||||
|
#include <timelineeditor/timelineicons.h>
|
||||||
|
|
||||||
|
#include <bindingproperty.h>
|
||||||
|
#include <nodeabstractproperty.h>
|
||||||
|
#include <nodemetainfo.h>
|
||||||
|
|
||||||
|
#include <qmldesignerplugin.h>
|
||||||
|
#include <qmlstate.h>
|
||||||
|
#include <qmltimeline.h>
|
||||||
|
|
||||||
|
#include <coreplugin/icore.h>
|
||||||
|
|
||||||
|
#include <theme.h>
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QComboBox>
|
||||||
|
#include <QGraphicsView>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMargins>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QResizeEvent>
|
||||||
|
#include <QScrollBar>
|
||||||
|
#include <QShowEvent>
|
||||||
|
#include <QSlider>
|
||||||
|
#include <QSpacerItem>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class Eventfilter : public QObject
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Eventfilter(QObject *parent)
|
||||||
|
: QObject(parent)
|
||||||
|
{}
|
||||||
|
|
||||||
|
bool eventFilter(QObject *, QEvent *event) override
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::Wheel) {
|
||||||
|
event->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TransitionEditorWidget::TransitionEditorWidget(TransitionEditorView *view)
|
||||||
|
: QWidget()
|
||||||
|
, m_toolbar(new TransitionEditorToolBar(this))
|
||||||
|
, m_rulerView(new QGraphicsView(this))
|
||||||
|
, m_graphicsView(new QGraphicsView(this))
|
||||||
|
, m_scrollbar(new QScrollBar(this))
|
||||||
|
, m_statusBar(new QLabel(this))
|
||||||
|
, m_transitionEditorView(view)
|
||||||
|
, m_graphicsScene(new TransitionEditorGraphicsScene(this))
|
||||||
|
, m_addButton(new QPushButton(this))
|
||||||
|
, m_onboardingContainer(new QWidget(this))
|
||||||
|
{
|
||||||
|
setWindowTitle(tr("Transition", "Title of transition view"));
|
||||||
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
const QString css = Theme::replaceCssColors(QString::fromUtf8(
|
||||||
|
Utils::FileReader::fetchQrc(QLatin1String(":/qmldesigner/scrollbar.css"))));
|
||||||
|
|
||||||
|
m_scrollbar->setStyleSheet(css);
|
||||||
|
m_scrollbar->setOrientation(Qt::Horizontal);
|
||||||
|
|
||||||
|
QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||||
|
sizePolicy1.setHorizontalStretch(0);
|
||||||
|
sizePolicy1.setVerticalStretch(0);
|
||||||
|
sizePolicy1.setHeightForWidth(m_graphicsView->sizePolicy().hasHeightForWidth());
|
||||||
|
|
||||||
|
m_rulerView->setObjectName("RulerView");
|
||||||
|
m_rulerView->setFixedHeight(TimelineConstants::rulerHeight);
|
||||||
|
m_rulerView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||||
|
m_rulerView->viewport()->installEventFilter(new Eventfilter(this));
|
||||||
|
m_rulerView->viewport()->setFocusPolicy(Qt::NoFocus);
|
||||||
|
m_rulerView->setStyleSheet(css);
|
||||||
|
m_rulerView->setFrameShape(QFrame::NoFrame);
|
||||||
|
m_rulerView->setFrameShadow(QFrame::Plain);
|
||||||
|
m_rulerView->setLineWidth(0);
|
||||||
|
m_rulerView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
m_rulerView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
m_rulerView->setScene(graphicsScene());
|
||||||
|
|
||||||
|
m_graphicsView->setStyleSheet(css);
|
||||||
|
m_graphicsView->setObjectName("SceneView");
|
||||||
|
m_graphicsView->setFrameShape(QFrame::NoFrame);
|
||||||
|
m_graphicsView->setFrameShadow(QFrame::Plain);
|
||||||
|
m_graphicsView->setLineWidth(0);
|
||||||
|
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||||
|
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||||
|
|
||||||
|
m_graphicsView->setSizePolicy(sizePolicy1);
|
||||||
|
m_graphicsView->setScene(graphicsScene());
|
||||||
|
m_graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||||
|
m_graphicsView->setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
|
||||||
|
|
||||||
|
auto *scrollBarLayout = new QHBoxLayout;
|
||||||
|
scrollBarLayout->addSpacing(TimelineConstants::sectionWidth);
|
||||||
|
scrollBarLayout->addWidget(m_scrollbar);
|
||||||
|
|
||||||
|
QMargins margins(0, 0, 0, QApplication::style()->pixelMetric(QStyle::PM_LayoutBottomMargin));
|
||||||
|
|
||||||
|
auto *contentLayout = new QVBoxLayout;
|
||||||
|
contentLayout->setContentsMargins(margins);
|
||||||
|
contentLayout->addWidget(m_rulerView);
|
||||||
|
contentLayout->addWidget(m_graphicsView);
|
||||||
|
contentLayout->addLayout(scrollBarLayout);
|
||||||
|
contentLayout->addWidget(m_statusBar);
|
||||||
|
m_statusBar->setIndent(2);
|
||||||
|
m_statusBar->setFixedHeight(TimelineConstants::rulerHeight);
|
||||||
|
|
||||||
|
auto *widgetLayout = new QVBoxLayout;
|
||||||
|
widgetLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
widgetLayout->setSpacing(0);
|
||||||
|
widgetLayout->addWidget(m_toolbar);
|
||||||
|
widgetLayout->addWidget(m_addButton);
|
||||||
|
|
||||||
|
m_addButton->setIcon(TimelineIcons::ADD_TIMELINE_TOOLBAR.icon());
|
||||||
|
m_addButton->setToolTip(tr("Add Transition"));
|
||||||
|
m_addButton->setFlat(true);
|
||||||
|
m_addButton->setFixedSize(32, 32);
|
||||||
|
|
||||||
|
widgetLayout->addWidget(m_onboardingContainer);
|
||||||
|
|
||||||
|
auto *onboardingTopLabel = new QLabel(m_onboardingContainer);
|
||||||
|
auto *onboardingBottomLabel = new QLabel(m_onboardingContainer);
|
||||||
|
auto *onboardingBottomIcon = new QLabel(m_onboardingContainer);
|
||||||
|
|
||||||
|
auto *onboardingLayout = new QVBoxLayout;
|
||||||
|
auto *onboardingSublayout = new QHBoxLayout;
|
||||||
|
auto *leftSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
auto *rightSpacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
|
||||||
|
auto *topSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||||
|
auto *bottomSpacer = new QSpacerItem(40, 20, QSizePolicy::Minimum, QSizePolicy::Expanding);
|
||||||
|
|
||||||
|
QString labelText = tr("This file does not contain transitions. <br><br> \
|
||||||
|
To create an animation, add a transition by clicking the + button.");
|
||||||
|
onboardingTopLabel->setText(labelText);
|
||||||
|
onboardingTopLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
|
||||||
|
|
||||||
|
m_onboardingContainer->setLayout(onboardingLayout);
|
||||||
|
onboardingLayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
onboardingLayout->setSpacing(0);
|
||||||
|
onboardingLayout->addSpacerItem(topSpacer);
|
||||||
|
onboardingLayout->addWidget(onboardingTopLabel);
|
||||||
|
onboardingLayout->addLayout(onboardingSublayout);
|
||||||
|
|
||||||
|
onboardingSublayout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
onboardingSublayout->setSpacing(0);
|
||||||
|
onboardingSublayout->addSpacerItem(leftSpacer);
|
||||||
|
|
||||||
|
onboardingBottomLabel->setAlignment(Qt::AlignRight | Qt::AlignTop);
|
||||||
|
onboardingBottomLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
onboardingSublayout->addWidget(onboardingBottomLabel);
|
||||||
|
onboardingBottomLabel->setText(tr("To edit the transition settings, click "));
|
||||||
|
|
||||||
|
onboardingBottomIcon->setAlignment(Qt::AlignLeft | Qt::AlignTop);
|
||||||
|
onboardingBottomIcon->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||||
|
onboardingSublayout->addWidget(onboardingBottomIcon);
|
||||||
|
onboardingBottomIcon->setPixmap(TimelineIcons::ANIMATION.pixmap());
|
||||||
|
|
||||||
|
onboardingSublayout->addSpacerItem(rightSpacer);
|
||||||
|
onboardingLayout->addSpacerItem(bottomSpacer);
|
||||||
|
|
||||||
|
widgetLayout->addLayout(contentLayout);
|
||||||
|
this->setLayout(widgetLayout);
|
||||||
|
|
||||||
|
connectToolbar();
|
||||||
|
|
||||||
|
auto setScrollOffset = [this]() { graphicsScene()->setScrollOffset(m_scrollbar->value()); };
|
||||||
|
connect(m_scrollbar, &QSlider::valueChanged, this, setScrollOffset);
|
||||||
|
|
||||||
|
connect(graphicsScene(),
|
||||||
|
&TransitionEditorGraphicsScene::statusBarMessageChanged,
|
||||||
|
this,
|
||||||
|
[this](const QString &message) { m_statusBar->setText(message); });
|
||||||
|
|
||||||
|
connect(m_addButton, &QPushButton::clicked, this, [this]() {
|
||||||
|
m_transitionEditorView->addNewTransition();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::setTransitionActive(bool b)
|
||||||
|
{
|
||||||
|
if (b) {
|
||||||
|
m_toolbar->setVisible(true);
|
||||||
|
m_graphicsView->setVisible(true);
|
||||||
|
m_rulerView->setVisible(true);
|
||||||
|
m_scrollbar->setVisible(true);
|
||||||
|
m_addButton->setVisible(false);
|
||||||
|
m_onboardingContainer->setVisible(false);
|
||||||
|
m_graphicsView->update();
|
||||||
|
m_rulerView->update();
|
||||||
|
} else {
|
||||||
|
m_toolbar->setVisible(false);
|
||||||
|
m_graphicsView->setVisible(false);
|
||||||
|
m_rulerView->setVisible(false);
|
||||||
|
m_scrollbar->setVisible(false);
|
||||||
|
m_addButton->setVisible(true);
|
||||||
|
m_onboardingContainer->setVisible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::connectToolbar()
|
||||||
|
{
|
||||||
|
connect(graphicsScene(),
|
||||||
|
&TransitionEditorGraphicsScene::selectionChanged,
|
||||||
|
this,
|
||||||
|
&TransitionEditorWidget::selectionChanged);
|
||||||
|
|
||||||
|
connect(m_toolbar,
|
||||||
|
&TransitionEditorToolBar::openEasingCurveEditor,
|
||||||
|
this,
|
||||||
|
&TransitionEditorWidget::openEasingCurveEditor);
|
||||||
|
|
||||||
|
connect(graphicsScene(),
|
||||||
|
&TransitionEditorGraphicsScene::scroll,
|
||||||
|
this,
|
||||||
|
&TransitionEditorWidget::scroll);
|
||||||
|
|
||||||
|
auto setRulerScaling = [this](int val) { m_graphicsScene->setRulerScaling(val); };
|
||||||
|
connect(m_toolbar, &TransitionEditorToolBar::scaleFactorChanged, setRulerScaling);
|
||||||
|
|
||||||
|
auto setDuration = [this](int end) { graphicsScene()->setDuration(end); };
|
||||||
|
connect(m_toolbar, &TransitionEditorToolBar::durationChanged, setDuration);
|
||||||
|
|
||||||
|
connect(m_toolbar,
|
||||||
|
&TransitionEditorToolBar::settingDialogClicked,
|
||||||
|
transitionEditorView(),
|
||||||
|
&TransitionEditorView::openSettingsDialog);
|
||||||
|
|
||||||
|
connect(m_toolbar,
|
||||||
|
&TransitionEditorToolBar::currentTransitionChanged,
|
||||||
|
this,
|
||||||
|
[this](const QString &transitionName) {
|
||||||
|
const ModelNode transition = transitionEditorView()->modelNodeForId(transitionName);
|
||||||
|
if (transition.isValid()) {
|
||||||
|
m_graphicsScene->setTransition(transition);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::changeScaleFactor(int factor)
|
||||||
|
{
|
||||||
|
m_toolbar->setScaleFactor(factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::scroll(const TimelineUtils::Side &side)
|
||||||
|
{
|
||||||
|
if (side == TimelineUtils::Side::Left)
|
||||||
|
m_scrollbar->setValue(m_scrollbar->value() - m_scrollbar->singleStep());
|
||||||
|
else if (side == TimelineUtils::Side::Right)
|
||||||
|
m_scrollbar->setValue(m_scrollbar->value() + m_scrollbar->singleStep());
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::selectionChanged()
|
||||||
|
{
|
||||||
|
if (graphicsScene()->selectedPropertyItem() != nullptr)
|
||||||
|
m_toolbar->setActionEnabled("Curve Picker", true);
|
||||||
|
else
|
||||||
|
m_toolbar->setActionEnabled("Curve Picker", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::contextHelp(const Core::IContext::HelpCallback &callback) const
|
||||||
|
{
|
||||||
|
if (transitionEditorView())
|
||||||
|
transitionEditorView()->contextHelp(callback);
|
||||||
|
else
|
||||||
|
callback({});
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::init()
|
||||||
|
{
|
||||||
|
ModelNode root = transitionEditorView()->rootModelNode();
|
||||||
|
ModelNode transition;
|
||||||
|
|
||||||
|
if (root.isValid() && root.hasProperty("transitions")) {
|
||||||
|
NodeAbstractProperty transitions = root.nodeAbstractProperty("transitions");
|
||||||
|
if (transitions.isValid())
|
||||||
|
transition = transitions.directSubNodes().first();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_graphicsScene->setTransition(transition);
|
||||||
|
setTransitionActive(transition.isValid());
|
||||||
|
|
||||||
|
m_graphicsScene->setWidth(m_graphicsView->viewport()->width());
|
||||||
|
|
||||||
|
m_toolbar->setScaleFactor(0);
|
||||||
|
|
||||||
|
m_toolbar->setCurrentTransition(transition);
|
||||||
|
|
||||||
|
qreal duration = 2000;
|
||||||
|
if (transition.isValid() && transition.hasAuxiliaryData("transitionDuration"))
|
||||||
|
duration = transition.auxiliaryData("transitionDuration").toDouble();
|
||||||
|
|
||||||
|
m_toolbar->setDuration(duration);
|
||||||
|
|
||||||
|
m_graphicsScene->setRulerScaling(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::updateData(const ModelNode &transition)
|
||||||
|
{
|
||||||
|
if (!transition.isValid()) {
|
||||||
|
init();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transition.metaInfo().isValid()
|
||||||
|
&& transition.metaInfo().isSubclassOf("QtQuick.Transition")) {
|
||||||
|
if (transition.id() == m_toolbar->currentTransitionId()) {
|
||||||
|
m_graphicsScene->setTransition(transition);
|
||||||
|
} else {
|
||||||
|
m_toolbar->updateComboBox(transition.view()->rootModelNode());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::reset()
|
||||||
|
{
|
||||||
|
graphicsScene()->clearTransition();
|
||||||
|
m_toolbar->reset();
|
||||||
|
m_statusBar->clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorGraphicsScene *TransitionEditorWidget::graphicsScene() const
|
||||||
|
{
|
||||||
|
return m_graphicsScene;
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorToolBar *TransitionEditorWidget::toolBar() const
|
||||||
|
{
|
||||||
|
return m_toolbar;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::setupScrollbar(int min, int max, int current)
|
||||||
|
{
|
||||||
|
bool b = m_scrollbar->blockSignals(true);
|
||||||
|
m_scrollbar->setMinimum(min);
|
||||||
|
m_scrollbar->setMaximum(max);
|
||||||
|
m_scrollbar->setValue(current);
|
||||||
|
m_scrollbar->setSingleStep((max - min) / 10);
|
||||||
|
m_scrollbar->blockSignals(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::showEvent(QShowEvent *event)
|
||||||
|
{
|
||||||
|
Q_UNUSED(event)
|
||||||
|
graphicsScene()->setWidth(m_graphicsView->viewport()->width());
|
||||||
|
graphicsScene()->invalidateLayout();
|
||||||
|
graphicsScene()->invalidate();
|
||||||
|
graphicsScene()->onShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::resizeEvent(QResizeEvent *event)
|
||||||
|
{
|
||||||
|
QWidget::resizeEvent(event);
|
||||||
|
graphicsScene()->setWidth(m_graphicsView->viewport()->width());
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionEditorView *TransitionEditorWidget::transitionEditorView() const
|
||||||
|
{
|
||||||
|
return m_transitionEditorView;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionEditorWidget::openEasingCurveEditor()
|
||||||
|
{
|
||||||
|
if (TransitionEditorPropertyItem *item = graphicsScene()->selectedPropertyItem()) {
|
||||||
|
QList<ModelNode> animations;
|
||||||
|
animations.append(item->propertyAnimation());
|
||||||
|
EasingCurveDialog::runDialog(animations, Core::ICore::dialogParent());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,103 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "timelineeditor/timelineutils.h"
|
||||||
|
|
||||||
|
#include <coreplugin/icontext.h>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
class TransitionEditorView;
|
||||||
|
class TransitionEditorToolBar;
|
||||||
|
class TransitionEditorGraphicsScene;
|
||||||
|
class ModelNode;
|
||||||
|
|
||||||
|
class TransitionEditorWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransitionEditorWidget(TransitionEditorView *view);
|
||||||
|
void contextHelp(const Core::IContext::HelpCallback &callback) const;
|
||||||
|
|
||||||
|
TransitionEditorGraphicsScene *graphicsScene() const;
|
||||||
|
TransitionEditorView *transitionEditorView() const;
|
||||||
|
TransitionEditorToolBar *toolBar() const;
|
||||||
|
|
||||||
|
void init();
|
||||||
|
void reset();
|
||||||
|
|
||||||
|
void setupScrollbar(int min, int max, int current);
|
||||||
|
void changeScaleFactor(int factor);
|
||||||
|
|
||||||
|
void updateData(const ModelNode &transition);
|
||||||
|
public slots:
|
||||||
|
void selectionChanged();
|
||||||
|
void scroll(const TimelineUtils::Side &side);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void showEvent(QShowEvent *event) override;
|
||||||
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void connectToolbar();
|
||||||
|
void setTransitionActive(bool b);
|
||||||
|
void openEasingCurveEditor();
|
||||||
|
|
||||||
|
TransitionEditorToolBar *m_toolbar = nullptr;
|
||||||
|
|
||||||
|
QGraphicsView *m_rulerView = nullptr;
|
||||||
|
|
||||||
|
QGraphicsView *m_graphicsView = nullptr;
|
||||||
|
|
||||||
|
QScrollBar *m_scrollbar = nullptr;
|
||||||
|
|
||||||
|
QLabel *m_statusBar = nullptr;
|
||||||
|
|
||||||
|
TransitionEditorView *m_transitionEditorView = nullptr;
|
||||||
|
|
||||||
|
TransitionEditorGraphicsScene *m_graphicsScene;
|
||||||
|
|
||||||
|
QPushButton *m_addButton = nullptr;
|
||||||
|
|
||||||
|
QWidget *m_onboardingContainer = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,211 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 "transitionform.h"
|
||||||
|
#include "timelineform.h"
|
||||||
|
#include "ui_transitionform.h"
|
||||||
|
|
||||||
|
#include <abstractview.h>
|
||||||
|
#include <bindingproperty.h>
|
||||||
|
#include <exception>
|
||||||
|
#include <nodelistproperty.h>
|
||||||
|
#include <nodemetainfo.h>
|
||||||
|
#include <rewritertransaction.h>
|
||||||
|
#include <variantproperty.h>
|
||||||
|
#include <qmlitemnode.h>
|
||||||
|
|
||||||
|
#include <coreplugin/messagebox.h>
|
||||||
|
|
||||||
|
#include <utils/algorithm.h>
|
||||||
|
#include <utils/qtcassert.h>
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
TransitionForm::TransitionForm(QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, ui(new Ui::TransitionForm)
|
||||||
|
{
|
||||||
|
ui->setupUi(this);
|
||||||
|
|
||||||
|
connect(ui->idLineEdit, &QLineEdit::editingFinished, [this]() {
|
||||||
|
QTC_ASSERT(m_transition.isValid(), return );
|
||||||
|
|
||||||
|
static QString lastString;
|
||||||
|
|
||||||
|
const QString newId = ui->idLineEdit->text();
|
||||||
|
|
||||||
|
if (newId == lastString)
|
||||||
|
return;
|
||||||
|
|
||||||
|
lastString = newId;
|
||||||
|
|
||||||
|
if (newId == m_transition.id())
|
||||||
|
return;
|
||||||
|
|
||||||
|
bool error = false;
|
||||||
|
|
||||||
|
if (!ModelNode::isValidId(newId)) {
|
||||||
|
Core::AsynchronousMessageBox::warning(tr("Invalid Id"),
|
||||||
|
tr("%1 is an invalid id.").arg(newId));
|
||||||
|
error = true;
|
||||||
|
} else if (m_transition.view()->hasId(newId)) {
|
||||||
|
Core::AsynchronousMessageBox::warning(tr("Invalid Id"),
|
||||||
|
tr("%1 already exists.").arg(newId));
|
||||||
|
error = true;
|
||||||
|
} else {
|
||||||
|
m_transition.setIdWithRefactoring(newId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
lastString.clear();
|
||||||
|
ui->idLineEdit->setText(m_transition.id());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->listWidgetTo, &QListWidget::itemChanged, this, [this]() {
|
||||||
|
QTC_ASSERT(m_transition.isValid(), return );
|
||||||
|
const QmlItemNode root(m_transition.view()->rootModelNode());
|
||||||
|
QTC_ASSERT(root.isValid(), return );
|
||||||
|
const int stateCount = root.states().names().count();
|
||||||
|
|
||||||
|
QStringList stateNames;
|
||||||
|
|
||||||
|
for (const QListWidgetItem *item : ui->listWidgetTo->findItems("*", Qt::MatchWildcard)) {
|
||||||
|
if (item->checkState() == Qt::Checked)
|
||||||
|
stateNames.append(item->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString toValue;
|
||||||
|
if (stateCount == stateNames.count())
|
||||||
|
toValue = "*";
|
||||||
|
else
|
||||||
|
toValue = stateNames.join(",");
|
||||||
|
|
||||||
|
m_transition.view()->executeInTransaction("TransitionForm::Set To", [this, toValue]() {
|
||||||
|
m_transition.variantProperty("to").setValue(toValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
connect(ui->listWidgetFrom, &QListWidget::itemChanged, this, [this]() {
|
||||||
|
QTC_ASSERT(m_transition.isValid(), return );
|
||||||
|
const QmlItemNode root(m_transition.view()->rootModelNode());
|
||||||
|
QTC_ASSERT(root.isValid(), return );
|
||||||
|
const int stateCount = root.states().names().count();
|
||||||
|
|
||||||
|
QStringList stateNames;
|
||||||
|
|
||||||
|
for (const QListWidgetItem *item : ui->listWidgetFrom->findItems("*", Qt::MatchWildcard)) {
|
||||||
|
if (item->checkState() == Qt::Checked)
|
||||||
|
stateNames.append(item->text());
|
||||||
|
}
|
||||||
|
|
||||||
|
QString fromValue;
|
||||||
|
if (stateCount == stateNames.count())
|
||||||
|
fromValue = "*";
|
||||||
|
else
|
||||||
|
fromValue = stateNames.join(",");
|
||||||
|
|
||||||
|
m_transition.view()->executeInTransaction("TransitionForm::Set To", [this, fromValue]() {
|
||||||
|
m_transition.variantProperty("from").setValue(fromValue);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
TransitionForm::~TransitionForm()
|
||||||
|
{
|
||||||
|
delete ui;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionForm::setTransition(const ModelNode &transition)
|
||||||
|
{
|
||||||
|
m_transition = transition;
|
||||||
|
|
||||||
|
if (m_transition.isValid()) {
|
||||||
|
ui->idLineEdit->setText(m_transition.displayName());
|
||||||
|
}
|
||||||
|
setupStatesLists();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelNode TransitionForm::transition() const
|
||||||
|
{
|
||||||
|
return m_transition;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TransitionForm::setupStatesLists()
|
||||||
|
{
|
||||||
|
bool bTo = ui->listWidgetTo->blockSignals(true);
|
||||||
|
bool bFrom = ui->listWidgetFrom->blockSignals(true);
|
||||||
|
QAbstractItemModel *modelTo = ui->listWidgetTo->model();
|
||||||
|
modelTo->removeRows(0, modelTo->rowCount());
|
||||||
|
|
||||||
|
QAbstractItemModel *modelFrom = ui->listWidgetFrom->model();
|
||||||
|
modelFrom->removeRows(0, modelFrom->rowCount());
|
||||||
|
|
||||||
|
bool starFrom = true;
|
||||||
|
bool starTo = true;
|
||||||
|
|
||||||
|
QStringList fromList;
|
||||||
|
QStringList toList;
|
||||||
|
|
||||||
|
if (m_transition.hasVariantProperty("from")
|
||||||
|
&& m_transition.variantProperty("from").value().toString().trimmed() != "*") {
|
||||||
|
starFrom = false;
|
||||||
|
fromList = m_transition.variantProperty("from").value().toString().split(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_transition.hasVariantProperty("to")
|
||||||
|
&& m_transition.variantProperty("to").value().toString().trimmed() != "*") {
|
||||||
|
starTo = false;
|
||||||
|
toList = m_transition.variantProperty("to").value().toString().split(",");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_transition.isValid()) {
|
||||||
|
const QmlItemNode root(m_transition.view()->rootModelNode());
|
||||||
|
if (root.isValid()) {
|
||||||
|
const QmlModelStateGroup states = root.states();
|
||||||
|
for (const QString &stateName : states.names()) {
|
||||||
|
auto itemTo = new QListWidgetItem(stateName, ui->listWidgetTo);
|
||||||
|
ui->listWidgetTo->addItem(itemTo);
|
||||||
|
itemTo->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
||||||
|
if (starTo || toList.contains(stateName))
|
||||||
|
itemTo->setCheckState(Qt::Checked);
|
||||||
|
else
|
||||||
|
itemTo->setCheckState(Qt::Unchecked);
|
||||||
|
|
||||||
|
auto itemFrom = new QListWidgetItem(stateName, ui->listWidgetFrom);
|
||||||
|
ui->listWidgetFrom->addItem(itemFrom);
|
||||||
|
itemFrom->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
|
||||||
|
if (starFrom || fromList.contains(stateName))
|
||||||
|
itemFrom->setCheckState(Qt::Checked);
|
||||||
|
else
|
||||||
|
itemFrom->setCheckState(Qt::Unchecked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ui->listWidgetTo->blockSignals(bTo);
|
||||||
|
ui->listWidgetFrom->blockSignals(bFrom);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,57 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** 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 <qmltimeline.h>
|
||||||
|
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
QT_FORWARD_DECLARE_CLASS(QSpinBox)
|
||||||
|
|
||||||
|
namespace QmlDesigner {
|
||||||
|
|
||||||
|
namespace Ui {
|
||||||
|
class TransitionForm;
|
||||||
|
}
|
||||||
|
|
||||||
|
class TransitionForm : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit TransitionForm(QWidget *parent);
|
||||||
|
~TransitionForm() override;
|
||||||
|
void setTransition(const ModelNode &transition);
|
||||||
|
ModelNode transition() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void setupStatesLists();
|
||||||
|
|
||||||
|
Ui::TransitionForm *ui;
|
||||||
|
ModelNode m_transition;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace QmlDesigner
|
@@ -0,0 +1,87 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<ui version="4.0">
|
||||||
|
<class>QmlDesigner::TransitionForm</class>
|
||||||
|
<widget class="QWidget" name="QmlDesigner::TransitionForm">
|
||||||
|
<property name="geometry">
|
||||||
|
<rect>
|
||||||
|
<x>0</x>
|
||||||
|
<y>0</y>
|
||||||
|
<width>641</width>
|
||||||
|
<height>170</height>
|
||||||
|
</rect>
|
||||||
|
</property>
|
||||||
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>160</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="font">
|
||||||
|
<font>
|
||||||
|
<weight>75</weight>
|
||||||
|
<bold>true</bold>
|
||||||
|
</font>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Timeline Settings</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1" colspan="2">
|
||||||
|
<widget class="QListWidget" name="listWidgetTo"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string>Transition ID:</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="3" colspan="2">
|
||||||
|
<spacer name="horizontalSpacer_11">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>49</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QListWidget" name="listWidgetFrom"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" colspan="2">
|
||||||
|
<widget class="QLineEdit" name="idLineEdit">
|
||||||
|
<property name="text">
|
||||||
|
<string/>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>From</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>To</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
<resources/>
|
||||||
|
<connections/>
|
||||||
|
</ui>
|
@@ -41,6 +41,7 @@
|
|||||||
#include <formeditor/transitiontool.h>
|
#include <formeditor/transitiontool.h>
|
||||||
#include <texttool/texttool.h>
|
#include <texttool/texttool.h>
|
||||||
#include <timelineeditor/timelineview.h>
|
#include <timelineeditor/timelineview.h>
|
||||||
|
#include <transitioneditor/transitioneditorview.h>
|
||||||
#include <pathtool/pathtool.h>
|
#include <pathtool/pathtool.h>
|
||||||
|
|
||||||
#include <qmljseditor/qmljseditor.h>
|
#include <qmljseditor/qmljseditor.h>
|
||||||
@@ -243,6 +244,10 @@ bool QmlDesignerPlugin::delayedInitialize()
|
|||||||
timelineView->registerActions();
|
timelineView->registerActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto transitionEditorView = new QmlDesigner::TransitionEditorView;
|
||||||
|
d->viewManager.registerViewTakingOwnership(transitionEditorView);
|
||||||
|
transitionEditorView->registerActions();
|
||||||
|
|
||||||
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::SourceTool);
|
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::SourceTool);
|
||||||
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::ColorTool);
|
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::ColorTool);
|
||||||
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::AnnotationTool);
|
d->viewManager.registerFormEditorToolTakingOwnership(new QmlDesigner::AnnotationTool);
|
||||||
|
@@ -32,6 +32,7 @@ include(components/curveeditor/curveeditor.pri)
|
|||||||
include(components/bindingeditor/bindingeditor.pri)
|
include(components/bindingeditor/bindingeditor.pri)
|
||||||
include(components/annotationeditor/annotationeditor.pri)
|
include(components/annotationeditor/annotationeditor.pri)
|
||||||
include(components/richtexteditor/richtexteditor.pri)
|
include(components/richtexteditor/richtexteditor.pri)
|
||||||
|
include(components/transitioneditor/transitioneditor.pri)
|
||||||
|
|
||||||
|
|
||||||
BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH)
|
BUILD_PUPPET_IN_CREATOR_BINPATH = $$(BUILD_PUPPET_IN_CREATOR_BINPATH)
|
||||||
|
@@ -843,6 +843,26 @@ Project {
|
|||||||
"timelineeditor/timelineview.h",
|
"timelineeditor/timelineview.h",
|
||||||
"timelineeditor/timelinewidget.cpp",
|
"timelineeditor/timelinewidget.cpp",
|
||||||
"timelineeditor/timelinewidget.h",
|
"timelineeditor/timelinewidget.h",
|
||||||
|
"transitioneditor/transitioneditorview.cpp",
|
||||||
|
"transitioneditor/transitioneditorview.h",
|
||||||
|
"transitioneditor/transitioneditorwidget.cpp",
|
||||||
|
"transitioneditor/transitioneditorwidget.h",
|
||||||
|
"transitioneditor/transitioneditortoolbar.cpp",
|
||||||
|
"transitioneditor/transitioneditortoolbar.h",
|
||||||
|
"transitioneditor/transitioneditorgraphicsscene.cpp",
|
||||||
|
"transitioneditor/transitioneditorgraphicsscene.h",
|
||||||
|
"transitioneditor/transitioneditorgraphicslayout.cpp",
|
||||||
|
"transitioneditor/transitioneditorgraphicslayout.h",
|
||||||
|
"transitioneditor/transitioneditorsectionitem.cpp",
|
||||||
|
"transitioneditor/transitioneditorsectionitem.h",
|
||||||
|
"transitioneditor/transitioneditorpropertyitem.cpp",
|
||||||
|
"transitioneditor/transitioneditorpropertyitem.h",
|
||||||
|
"transitioneditor/transitioneditorsettingsdialog.cpp",
|
||||||
|
"transitioneditor/transitioneditorsettingsdialog.h",
|
||||||
|
"transitioneditor/transitioneditorsettingsdialog.ui"
|
||||||
|
"transitioneditor/transitionform.cpp",
|
||||||
|
"transitioneditor/transitionform.h",
|
||||||
|
"transitioneditor/transitioneditor.qrc"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user