summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMahmoud Badri <mahmoud.badri@qt.io>2019-08-07 14:35:53 +0300
committerMahmoud Badri <mahmoud.badri@qt.io>2019-08-08 09:48:28 +0300
commit40987cdef2196c8c59646e16af52b60e469f81ed (patch)
tree572a4390481b6e272eea65498e3cd290ac0985fa /src
parent062382bcac16fe0258b57ed94465fc6092fc5c1a (diff)
Separate bezier curve channels
- enable toggling a channel's visibility. - each channel has its own bezier controls. Task-number: QT3DS-3813 Change-Id: I4e0a4ec4b84c0ae570c134fe6ffd430f9ad4daa4 Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io> Reviewed-by: Tomi Korpipää <tomi.korpipaa@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp6
-rw-r--r--src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h4
-rw-r--r--src/Authoring/Client/Code/Core/Utility/HotKeys.cpp10
-rw-r--r--src/Authoring/Client/Code/Core/Utility/HotKeys.h2
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h2
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp29
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h2
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp51
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h4
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowManager.cpp3
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp2
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp346
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h3
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp84
-rw-r--r--src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h4
15 files changed, 288 insertions, 264 deletions
diff --git a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
index 854bf116..04588dfc 100644
--- a/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
+++ b/src/Authoring/Client/Code/Core/Doc/DocumentEditor.cpp
@@ -2842,11 +2842,9 @@ public:
m_AnimationCore.SetKeyframeData(inKeyframe, kfData);
}
- void setBezierKeyframeValues(const QVector<std::pair<qt3dsdm::Qt3DSDMKeyframeHandle,
- TKeyframe>> &changedKfs) override
+ void setBezierKeyframeValue(TKeyframeHandle kfHandle, const TKeyframe &kfData) override
{
- for (auto kf : changedKfs)
- m_AnimationCore.SetKeyframeData(kf.first, kf.second);
+ m_AnimationCore.SetKeyframeData(kfHandle, kfData);
}
void DeleteAllKeyframes(Qt3DSDMAnimationHandle inAnimation) override
diff --git a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h
index d1b655de..2378d713 100644
--- a/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h
+++ b/src/Authoring/Client/Code/Core/Doc/IDocumentEditor.h
@@ -307,8 +307,8 @@ public:
virtual bool RemoveAnimation(TSlideHandle inSlide, TInstanceHandle instance,
const wchar_t *propName, long subIndex) = 0;
virtual void SetKeyframeTime(TKeyframeHandle inKeyframe, long inTimeInMilliseconds) = 0;
- virtual void setBezierKeyframeValues(const QVector<std::pair<TKeyframeHandle,
- qt3dsdm::TKeyframe>> &changedKfs) = 0;
+ virtual void setBezierKeyframeValue(TKeyframeHandle kfHandle,
+ const qt3dsdm::TKeyframe &kfData) = 0;
virtual void DeleteAllKeyframes(Qt3DSDMAnimationHandle inAnimation) = 0;
virtual void KeyframeProperty(Qt3DSDMInstanceHandle inInstance, Qt3DSDMPropertyHandle inProperty,
bool inDoDiffValue) = 0;
diff --git a/src/Authoring/Client/Code/Core/Utility/HotKeys.cpp b/src/Authoring/Client/Code/Core/Utility/HotKeys.cpp
index a47c2eb8..278bf23b 100644
--- a/src/Authoring/Client/Code/Core/Utility/HotKeys.cpp
+++ b/src/Authoring/Client/Code/Core/Utility/HotKeys.cpp
@@ -566,6 +566,16 @@ bool CHotKeys::IsKeyDown(Qt::KeyboardModifier inKeyCode)
return qApp->keyboardModifiers() & inKeyCode;
}
+bool CHotKeys::isCtrlDown()
+{
+ return qApp->keyboardModifiers() & Qt::ControlModifier;
+}
+
+bool CHotKeys::isAltDown()
+{
+ return qApp->keyboardModifiers() & Qt::AltModifier;
+}
+
//=============================================================================
/**
* Retrieves the current status of the various modifier keys.
diff --git a/src/Authoring/Client/Code/Core/Utility/HotKeys.h b/src/Authoring/Client/Code/Core/Utility/HotKeys.h
index 75376322..27dc8fb9 100644
--- a/src/Authoring/Client/Code/Core/Utility/HotKeys.h
+++ b/src/Authoring/Client/Code/Core/Utility/HotKeys.h
@@ -238,6 +238,8 @@ public:
void ReleaseHotKeys();
static bool IsKeyDown(Qt::KeyboardModifier inKeyCode);
+ static bool isCtrlDown();
+ static bool isAltDown();
static Qt::KeyboardModifiers GetCurrentKeyModifiers();
static bool isFocusOnControlThatWantsKeys();
diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h
index 4754bb0d..cdfbd0f1 100644
--- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h
+++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/ITimelineItemProperty.h
@@ -50,8 +50,6 @@ public:
virtual Q3DStudio::CString GetName() const = 0;
virtual bool IsMaster() const = 0;
virtual qt3dsdm::TDataTypePair GetType() const = 0;
- virtual float GetMaximumValue() const = 0;
- virtual float GetMinimumValue() const = 0;
virtual void SetSelected() = 0;
virtual void DeleteAllKeys() = 0;
diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp
index f863435c..182f9d78 100644
--- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp
+++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.cpp
@@ -188,35 +188,6 @@ qt3dsdm::TDataTypePair Qt3DSDMTimelineItemProperty::GetType() const
return m_Type;
}
-void CompareAndSet(const Qt3DSDMTimelineKeyframe *inKeyframe, float &outRetValue, bool inGreaterThan)
-{
- float theValue = (inGreaterThan) ? inKeyframe->GetMaxValue() : inKeyframe->GetMinValue();
- if ((inGreaterThan && theValue > outRetValue) || (!inGreaterThan && theValue < outRetValue))
- outRetValue = theValue;
-}
-
-// returns the max keyframe value in a property. For bezier keyframes this includes the control
-// points values as well
-float Qt3DSDMTimelineItemProperty::GetMaximumValue() const
-{
- float theRetVal = FLT_MIN;
- do_all(m_Keyframes, std::bind(CompareAndSet, std::placeholders::_1, std::ref(theRetVal), true));
- if (m_Type.first == DataModelDataType::Float4 && m_Type.second == AdditionalMetaDataType::Color)
- theRetVal = DataModelToColor(theRetVal);
- return theRetVal;
-}
-
-// returns the min keyframe value in a property. For bezier keyframes this includes the control
-// points values as well
-float Qt3DSDMTimelineItemProperty::GetMinimumValue() const
-{
- float theRetVal = FLT_MAX;
- do_all(m_Keyframes, std::bind(CompareAndSet, std::placeholders::_1, std::ref(theRetVal), false));
- if (m_Type.first == DataModelDataType::Float4 && m_Type.second == AdditionalMetaDataType::Color)
- theRetVal = DataModelToColor(theRetVal);
- return theRetVal;
-}
-
RowTree *Qt3DSDMTimelineItemProperty::getRowTree() const
{
return m_rowTree;
diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h
index ff508ae8..e386fe38 100644
--- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h
+++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineItemProperty.h
@@ -61,8 +61,6 @@ public:
Q3DStudio::CString GetName() const override;
bool IsMaster() const override;
qt3dsdm::TDataTypePair GetType() const override;
- float GetMaximumValue() const override;
- float GetMinimumValue() const override;
void SetSelected() override;
void DeleteAllKeys() override;
IKeyframe *GetKeyframeByTime(long inTime) const override;
diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp
index d8d7aad3..c7431b3b 100644
--- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp
+++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.cpp
@@ -192,54 +192,3 @@ void Qt3DSDMTimelineKeyframe::GetKeyframeHandles(TKeyframeHandleList &outList) c
{
outList = m_KeyframeHandles;
}
-
-void CompareAndSet(Qt3DSDMKeyframeHandle inKeyframe, IAnimationCore *inAnimationCore,
- float &ioRetValue, bool inGreaterThan)
-{
- TKeyframe keyframeData = inAnimationCore->GetKeyframeData(inKeyframe);
- float value = KeyframeValueValue(keyframeData);
- if ((inGreaterThan && value > ioRetValue) || (!inGreaterThan && value < ioRetValue))
- ioRetValue = value;
-
- // for bezier keyframes compare tangents in/out also
- if (keyframeData.getType() == qt3dsdm::EAnimationTypeBezier) {
- float inTime, inValue, outTime, outValue;
- getBezierValues(keyframeData, inTime, inValue, outTime, outValue);
-
- if (!inAnimationCore->IsFirstKeyframe(inKeyframe) // check tangent-in value
- && ((inGreaterThan && inValue > ioRetValue)
- || (!inGreaterThan && inValue < ioRetValue))) {
- ioRetValue = inValue;
- }
-
- if (!inAnimationCore->IsLastKeyframe(inKeyframe) // check tangent-out value
- && ((inGreaterThan && outValue > ioRetValue)
- || (!inGreaterThan && outValue < ioRetValue))) {
- ioRetValue = outValue;
- }
- }
-}
-
-// returns the max keyframe channel value. For bezier keyframes this includes the control
-// points values as well
-float Qt3DSDMTimelineKeyframe::GetMaxValue() const
-{
- IAnimationCore *animCore = m_Doc->GetStudioSystem()->GetAnimationCore();
- float theRetVal = FLT_MIN;
- do_all(m_KeyframeHandles,
- std::bind(CompareAndSet, std::placeholders::_1, animCore, std::ref(theRetVal), true));
-
- return theRetVal;
-}
-
-// returns the min keyframe channel value. For bezier keyframes this includes the control
-// points values as well
-float Qt3DSDMTimelineKeyframe::GetMinValue() const
-{
- IAnimationCore *animCore = m_Doc->GetStudioSystem()->GetAnimationCore();
- float theRetVal = FLT_MAX;
- do_all(m_KeyframeHandles,
- std::bind(CompareAndSet, std::placeholders::_1, animCore, std::ref(theRetVal), false));
-
- return theRetVal;
-}
diff --git a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h
index 7799cc0d..99596c84 100644
--- a/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h
+++ b/src/Authoring/Qt3DStudio/Palettes/Timeline/Bindings/Qt3DSDMTimelineKeyframe.h
@@ -78,10 +78,6 @@ public:
void UpdateKeyframesTime(COffsetKeyframesCommandHelper *inCommandHelper, long inTime);
void GetKeyframeHandles(TKeyframeHandleList &outList) const;
- // support drawing graphs
- float GetMaxValue() const;
- float GetMinValue() const;
-
static float GetTimeInSecs(long inTime);
};
diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowManager.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowManager.cpp
index 50eff996..6dd0f991 100644
--- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowManager.cpp
+++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/RowManager.cpp
@@ -219,6 +219,9 @@ void RowManager::selectRow(RowTree *row, bool multiSelect)
if (row->locked())
return;
+ if (multiSelect && row->propertyExpanded())
+ return;
+
if (row->isProperty())
row = row->parentRow();
diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
index f33cf263..63b347b6 100644
--- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
+++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/TimelineGraphicsScene.cpp
@@ -539,7 +539,7 @@ void TimelineGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event)
// Prepare to change selection to single selection at release if a multiselected
// row is clicked without ctrl.
if (!ctrlKeyDown && m_rowManager->isRowSelected(rowTree)
- && !m_rowManager->isSingleSelected() ) {
+ && !m_rowManager->isSingleSelected()) {
m_releaseSelectRow = rowTree;
}
m_rowManager->selectRow(rowTree, ctrlKeyDown);
diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
index 6c6c6f86..b2587864 100644
--- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
+++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.cpp
@@ -76,107 +76,114 @@ void RowTimelinePropertyGraph::paintGraphs(QPainter *painter, const QRectF &rect
painter->setPen(QPen(CStudioPreferences::studioColor3()));
painter->drawLine(edgeOffset.x(), m_graphY, rect.right(), m_graphY);
- // draw channel curves
+ // draw channel curves and control points (for bezier)
auto animHandles = m_propBinding->animationHandles();
+ bool isBezier = m_rowTimeline->rowTree()->propBinding()->animationType()
+ == EAnimationTypeBezier;
for (size_t channelIndex = 0; channelIndex < animHandles.size(); ++channelIndex) {
- // Mahmoud_TODO: this block will draw the channel curves without sampling which is more
- // efficient, but it cannot be used till the bezier equation is fixed (check:QT3DS-3777)
- //-------------------------------draw using cubicTo --------------------------------------
-// QPainterPath path2;
-// Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
-// m_animCore->GetKeyframes(animHandles[channelIndex], keyframeHandles);
-// if (!keyframeHandles.empty()) {
-// TKeyframe kf0 = m_animCore->GetKeyframeData(keyframeHandles[0]);
-// path2.moveTo(getKeyframePosition(GetKeyframeSeconds(kf0), KeyframeValueValue(kf0))
-// + edgeOffset);
-
-// for (int i = 1; i < keyframeHandles.size(); ++i) {
-// TKeyframe kf1 = m_animCore->GetKeyframeData(keyframeHandles[i]);
-// float kf0InTime = -1, kf0InValue, kf0OutTime, kf0OutValue;
-// float kf1InTime = -1, kf1InValue, kf1OutTime, kf1OutValue;
-// getBezierValues(kf0, kf0InTime, kf0InValue, kf0OutTime, kf0OutValue);
-// getBezierValues(kf1, kf1InTime, kf1InValue, kf1OutTime, kf1OutValue);
-// if (kf0InTime != -1) {
-// path2.cubicTo(getKeyframePosition(kf0OutTime, kf0OutValue) + edgeOffset,
-// getKeyframePosition(kf1InTime, kf1InValue) + edgeOffset,
-// getKeyframePosition(GetKeyframeSeconds(kf1),
-// KeyframeValueValue(kf1))
-// + edgeOffset);
-// } else {
-// path2.lineTo(getKeyframePosition(GetKeyframeSeconds(kf1),
-// KeyframeValueValue(kf1))
-// + edgeOffset);
+ if (m_rowTimeline->rowTree()->channelActive(channelIndex)) {
+ // draw channel curve
+ // Mahmoud_TODO: this block will draw the channel curves without sampling which is more
+ // efficient, but it cannot be used till the bezier equation is fixed (check:QT3DS-3777)
+ //-------------------------------draw using cubicTo ------------------------------------
+// QPainterPath path2;
+// Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
+// m_animCore->GetKeyframes(animHandles[channelIndex], keyframeHandles);
+// if (!keyframeHandles.empty()) {
+// TKeyframe kf0 = m_animCore->GetKeyframeData(keyframeHandles[0]);
+// path2.moveTo(getKeyframePosition(GetKeyframeSeconds(kf0), KeyframeValueValue(kf0))
+// + edgeOffset);
+
+// for (int i = 1; i < keyframeHandles.size(); ++i) {
+// TKeyframe kf1 = m_animCore->GetKeyframeData(keyframeHandles[i]);
+// float kf0InTime = -1, kf0InValue, kf0OutTime, kf0OutValue;
+// float kf1InTime = -1, kf1InValue, kf1OutTime, kf1OutValue;
+// getBezierValues(kf0, kf0InTime, kf0InValue, kf0OutTime, kf0OutValue);
+// getBezierValues(kf1, kf1InTime, kf1InValue, kf1OutTime, kf1OutValue);
+// if (kf0InTime != -1) {
+// path2.cubicTo(getKeyframePosition(kf0OutTime, kf0OutValue) + edgeOffset,
+// getKeyframePosition(kf1InTime, kf1InValue) + edgeOffset,
+// getKeyframePosition(GetKeyframeSeconds(kf1),
+// KeyframeValueValue(kf1))
+// + edgeOffset);
+// } else {
+// path2.lineTo(getKeyframePosition(GetKeyframeSeconds(kf1),
+// KeyframeValueValue(kf1))
+// + edgeOffset);
+// }
+// // Mahmoud_TODO: handle ease in/out curves as well
+// kf0 = kf1;
// }
-// // Mahmoud_TODO: handle ease in/out curves as well
-// kf0 = kf1;
+// painter->setPen(QPen(QColor("#ff0000"), 1));
+// painter->drawPath(path2);
// }
-// painter->setPen(QPen(QColor("#ff0000"), 1));
-// painter->drawPath(path2);
-// }
- //-------------------------------draw using cubicTo --------------------------------------
-
- QPainterPath path;
- int start_i = qMax(rect.x(), edgeOffset.x());
- for (int i = start_i; i < rect.right(); i += 5) { // 5 = sampling step in pixels
- // Value time in ms
- long time = (i - edgeOffset.x()) / (TimelineConstants::RULER_MILLI_W * timelineScale);
- qreal value = m_propBinding->GetChannelValueAtTime(channelIndex, time);
- qreal yPos = m_graphY - value * m_valScale;
- if (i == start_i)
- path.moveTo(i, yPos);
- else
- path.lineTo(i, yPos);
- }
- QColor channelColor;
- if (channelIndex == 0)
- channelColor = CStudioPreferences::GetXAxisColor();
- else if (channelIndex == 1)
- channelColor = CStudioPreferences::GetYAxisColor();
- else if (channelIndex == 2)
- channelColor = CStudioPreferences::GetZAxisColor();
- painter->setPen(QPen(channelColor, 2));
- painter->drawPath(path);
- }
-
- // draw bezier controls
- if (m_rowTimeline->rowTree()->propBinding()->animationType() == EAnimationTypeBezier) {
- static const QPixmap pixBezierHandle = QPixmap("://images/breadcrumb_component_button.png");
- static const QPixmap pixBezierHandlePressed = QPixmap("://images/breadcrumb_component_grey"
- "_button.png");
-
- Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
- m_animCore->GetKeyframes(animHandles[0], keyframeHandles);
-
- size_t kfHandlesSize = keyframeHandles.size();
- for (size_t i = 0; i < kfHandlesSize; ++i) {
- SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData(
- keyframeHandles[i]));
-
- QPointF centerPos = getBezierControlPosition(kf) + edgeOffset;
- const QPointF PIX_HALF_W = QPointF(8.0, 8.0);
-
- // draw vertical keyframe separator line
- painter->setPen(QPen(CStudioPreferences::studioColor2(), 1));
- painter->drawLine(centerPos.x(), rect.y(), centerPos.x(), rect.height());
-
- // draw tangent-in part
- painter->setPen(CStudioPreferences::getBezierControlColor());
- if (i > 0) {
- QPointF cInPos = getBezierControlPosition(kf, BezierControlType::In) + edgeOffset;
- painter->drawLine(cInPos, centerPos);
- painter->drawPixmap(cInPos - PIX_HALF_W, pixBezierHandle);
+ //-------------------------------draw using cubicTo ------------------------------------
+
+ QPainterPath path;
+ int start_i = qMax(rect.x(), edgeOffset.x());
+ for (int i = start_i; i < rect.right(); i += 5) { // 5 = sampling step in pixels
+ // Value time in ms
+ long time = (i - edgeOffset.x()) / (RULER_MILLI_W * timelineScale);
+ qreal value = m_propBinding->GetChannelValueAtTime(channelIndex, time);
+ qreal yPos = m_graphY - value * m_valScale;
+ if (i == start_i)
+ path.moveTo(i, yPos);
+ else
+ path.lineTo(i, yPos);
}
-
- // draw tangent-out part
- if (i < kfHandlesSize - 1) {
- QPointF cOutPos = getBezierControlPosition(kf, BezierControlType::Out) + edgeOffset;
- painter->drawLine(cOutPos, centerPos);
- painter->drawPixmap(cOutPos - PIX_HALF_W, pixBezierHandle);
+ QColor channelColor;
+ if (channelIndex == 0)
+ channelColor = CStudioPreferences::GetXAxisColor();
+ else if (channelIndex == 1)
+ channelColor = CStudioPreferences::GetYAxisColor();
+ else if (channelIndex == 2)
+ channelColor = CStudioPreferences::GetZAxisColor();
+ painter->setPen(QPen(channelColor, 2));
+ painter->drawPath(path);
+
+ // draw bezier control points
+ if (isBezier) {
+ static const QPixmap pixBezierHandle("://images/breadcrumb_component_button.png");
+ static const QPixmap pixBezierHandlePressed("://images/breadcrumb_component_grey"
+ "_button.png");
+
+ Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
+ m_animCore->GetKeyframes(animHandles[channelIndex], keyframeHandles);
+
+ size_t kfHandlesSize = keyframeHandles.size();
+ for (size_t i = 0; i < kfHandlesSize; ++i) {
+ SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData(
+ keyframeHandles[i]));
+
+ QPointF centerPos = getBezierControlPosition(kf) + edgeOffset;
+ const QPointF PIX_HALF_W = QPointF(8.0, 8.0);
+
+ // draw vertical keyframe separator line
+ painter->setPen(QPen(CStudioPreferences::studioColor2(), 1));
+ painter->drawLine(centerPos.x(), rect.y(), centerPos.x(), rect.height());
+
+ // draw tangent-in part
+ painter->setPen(CStudioPreferences::getBezierControlColor());
+ if (i > 0) {
+ QPointF cInPos = getBezierControlPosition(kf, BezierControlType::In)
+ + edgeOffset;
+ painter->drawLine(cInPos, centerPos);
+ painter->drawPixmap(cInPos - PIX_HALF_W, pixBezierHandle);
+ }
+
+ // draw tangent-out part
+ if (i < kfHandlesSize - 1) {
+ QPointF cOutPos = getBezierControlPosition(kf, BezierControlType::Out)
+ + edgeOffset;
+ painter->drawLine(cOutPos, centerPos);
+ painter->drawPixmap(cOutPos - PIX_HALF_W, pixBezierHandle);
+ }
+
+ // draw center point
+ painter->setPen(QPen(CStudioPreferences::getBezierControlColor(), 3));
+ painter->drawPoint(centerPos);
+ }
}
-
- // draw center point
- painter->setPen(QPen(CStudioPreferences::getBezierControlColor(), 3));
- painter->drawPoint(centerPos);
}
}
}
@@ -194,28 +201,29 @@ TimelineControlType RowTimelinePropertyGraph::getClickedBezierControl(const QPoi
if (m_rowTimeline->rowTree()->propBinding()->animationType() != EAnimationTypeBezier)
return TimelineControlType::None;
- m_currKeyframeHandles.clear();
- m_currKeyframeData.clear();
+ m_currKeyframeData.first = 0; // reset the data
auto animHandles = m_propBinding->animationHandles();
- Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
- m_animCore->GetKeyframes(animHandles[0], keyframeHandles);
- const double CONTROL_RADIUS = 8;
- for (auto kfHandle : keyframeHandles) {
- SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData(kfHandle));
-
- QPointF cInPos = getBezierControlPosition(kf, BezierControlType::In);
- QPointF cOutPos = getBezierControlPosition(kf, BezierControlType::Out);
- bool clickedInHandle = QLineF(cInPos, pos).length() < CONTROL_RADIUS;
- bool clickedOutHandle = QLineF(cOutPos, pos).length() < CONTROL_RADIUS;
- if (clickedInHandle || clickedOutHandle) {
- m_rowTimeline->rowTree()->propBinding()->GetKeyframeByTime(kf.m_KeyframeSeconds * 1000)
- ->getUI()->binding->GetKeyframeHandles(m_currKeyframeHandles);
- for (auto h : m_currKeyframeHandles)
- m_currKeyframeData.append({h, m_animCore->GetKeyframeData(h)});
-
- return clickedInHandle ? TimelineControlType::BezierInHandle
- : TimelineControlType::BezierOutHandle;
+ for (size_t chIndex = 0; chIndex < animHandles.size(); ++chIndex) {
+ if (m_rowTimeline->rowTree()->channelActive(chIndex)) {
+ Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
+ m_animCore->GetKeyframes(animHandles[chIndex], keyframeHandles);
+ const double CONTROL_RADIUS = 8;
+ for (auto kfHandle : keyframeHandles) {
+ SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData(kfHandle));
+
+ QPointF cInPos = getBezierControlPosition(kf, BezierControlType::In);
+ QPointF cOutPos = getBezierControlPosition(kf, BezierControlType::Out);
+ bool clickedInHandle = QLineF(cInPos, pos).length() < CONTROL_RADIUS;
+ bool clickedOutHandle = QLineF(cOutPos, pos).length() < CONTROL_RADIUS;
+ if (clickedInHandle || clickedOutHandle) {
+ m_currKeyframeData.first = kfHandle;
+ m_currKeyframeData.second = m_animCore->GetKeyframeData(kfHandle);
+
+ return clickedInHandle ? TimelineControlType::BezierInHandle
+ : TimelineControlType::BezierOutHandle;
+ }
+ }
}
}
@@ -258,29 +266,27 @@ QPointF RowTimelinePropertyGraph::getKeyframePosition(float time, float value) c
void RowTimelinePropertyGraph::updateBezierControlValue(TimelineControlType controlType,
const QPointF &scenePos)
{
- QPointF p = m_rowTimeline->mapFromScene(scenePos.x() - TimelineConstants::RULER_EDGE_OFFSET,
- scenePos.y());
+ QPointF p = m_rowTimeline->mapFromScene(scenePos.x() - RULER_EDGE_OFFSET, scenePos.y());
+ // time and value at current mouse position
float time = m_rowTimeline->rowTree()->m_scene->ruler()->distanceToTime(p.x()) / 1000.f; // secs
float value = (m_graphY - p.y()) / m_valScale;
- // first channel keyframe
- SBezierKeyframe kf0 = get<SBezierKeyframe>(m_animCore->GetKeyframeData(
- m_currKeyframeHandles[0]));
+ SBezierKeyframe kf = get<SBezierKeyframe>(m_currKeyframeData.second);
bool isBezierIn = controlType == TimelineControlType::BezierInHandle;
// prevent handles from moving to the other side of the keyframe
- if ((isBezierIn && time > kf0.m_KeyframeSeconds)
- || (!isBezierIn && time < kf0.m_KeyframeSeconds)) {
- time = kf0.m_KeyframeSeconds;
+ if ((isBezierIn && time > kf.m_KeyframeSeconds)
+ || (!isBezierIn && time < kf.m_KeyframeSeconds)) {
+ time = kf.m_KeyframeSeconds;
}
// prevent handles from going beyond prev. and next keyframes
- auto animHandles = m_propBinding->animationHandles();
+ Qt3DSDMAnimationHandle anim = m_animCore->GetAnimationForKeyframe(m_currKeyframeData.first);
Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
- m_animCore->GetKeyframes(animHandles[0], keyframeHandles);
+ m_animCore->GetKeyframes(anim, keyframeHandles);
for (size_t i = 0; i < keyframeHandles.size(); ++i) {
- if (keyframeHandles[i] == m_currKeyframeHandles[0]) {
+ if (keyframeHandles[i] == m_currKeyframeData.first) {
float currKfTime = KeyframeTime(m_animCore->GetKeyframeData(keyframeHandles[i]));
float prevKfTime = i > 0
? KeyframeTime(m_animCore->GetKeyframeData(keyframeHandles[i - 1])) : -FLT_MAX;
@@ -289,41 +295,32 @@ void RowTimelinePropertyGraph::updateBezierControlValue(TimelineControlType cont
if (isBezierIn) {
if (time < prevKfTime)
time = prevKfTime;
- if (!CHotKeys::IsKeyDown(Qt::ControlModifier)
- && time < currKfTime * 2 - nextKfTime) {
+ if (!CHotKeys::isCtrlDown() && time < currKfTime * 2 - nextKfTime)
time = currKfTime * 2 - nextKfTime;
- }
} else { // bezier out
if (time > nextKfTime)
time = nextKfTime;
- if (!CHotKeys::IsKeyDown(Qt::ControlModifier)
- && time > currKfTime * 2 - prevKfTime) {
+ if (!CHotKeys::isCtrlDown() && time > currKfTime * 2 - prevKfTime)
time = currKfTime * 2 - prevKfTime;
- }
}
break;
}
}
- for (size_t i = 0; i < m_currKeyframeHandles.size(); ++i) {
- SBezierKeyframe kf = get<SBezierKeyframe>(m_animCore->GetKeyframeData(
- m_currKeyframeHandles[i]));
- float &currHandleTime = isBezierIn ? kf.m_InTangentTime : kf.m_OutTangentTime;
- float &currHandleValue = isBezierIn ? kf.m_InTangentValue : kf.m_OutTangentValue;
- float &otherHandleTime = isBezierIn ? kf.m_OutTangentTime : kf.m_InTangentTime;
- float &otherHandleValue = isBezierIn ? kf.m_OutTangentValue : kf.m_InTangentValue;
+ float &currHandleTime = isBezierIn ? kf.m_InTangentTime : kf.m_OutTangentTime;
+ float &currHandleValue = isBezierIn ? kf.m_InTangentValue : kf.m_OutTangentValue;
+ float &otherHandleTime = isBezierIn ? kf.m_OutTangentTime : kf.m_InTangentTime;
+ float &otherHandleValue = isBezierIn ? kf.m_OutTangentValue : kf.m_InTangentValue;
- currHandleTime = time;
- currHandleValue = value + (kf.m_KeyframeValue - kf0.m_KeyframeValue);
+ currHandleTime = time;
+ currHandleValue = value;
- if (!CHotKeys::IsKeyDown(Qt::ControlModifier)) {
- otherHandleTime = kf.m_KeyframeSeconds + (kf.m_KeyframeSeconds - time);
- otherHandleValue = kf.m_KeyframeValue + (kf.m_KeyframeValue - currHandleValue);
- }
-
- m_animCore->SetKeyframeData(m_currKeyframeHandles[i], kf);
+ if (!CHotKeys::isCtrlDown()) {
+ otherHandleTime = kf.m_KeyframeSeconds + (kf.m_KeyframeSeconds - time);
+ otherHandleValue = kf.m_KeyframeValue + (kf.m_KeyframeValue - currHandleValue);
}
+ m_animCore->SetKeyframeData(m_currKeyframeData.first, kf);
}
// adjust graph scale and y so that all keyframe and control points are visible
@@ -333,8 +330,47 @@ void RowTimelinePropertyGraph::fitGraph()
m_graphY = m_rowTimeline->size().height() - MARGIN_Y;
m_graphH = m_rowTimeline->size().height() - MARGIN_Y * 2;
- m_valScale = m_graphH / (m_propBinding->GetMaximumValue() - m_propBinding->GetMinimumValue());
- m_graphY += m_propBinding->GetMinimumValue() * m_valScale;
+ // get min/max keyframes values in the active channels
+ float minVal = FLT_MAX;
+ float maxVal = -FLT_MAX;
+ const auto animHandles = m_propBinding->animationHandles();
+ for (int i = 0; i < animHandles.size(); ++i) {
+ if (m_rowTimeline->rowTree()->channelActive(i)) {
+ Qt3DSDMTimelineKeyframe::TKeyframeHandleList keyframeHandles;
+ m_animCore->GetKeyframes(animHandles[i], keyframeHandles);
+ for (auto kfHandle : keyframeHandles) {
+ TKeyframe keyframeData = m_animCore->GetKeyframeData(kfHandle);
+ float value = KeyframeValueValue(keyframeData);
+ if (value < minVal)
+ minVal = value;
+ if (value > maxVal)
+ maxVal = value;
+
+ // for bezier keyframes compare tangents in/out also
+ if (keyframeData.getType() == qt3dsdm::EAnimationTypeBezier) {
+ float timeIn, valueIn, timeOut, valueOut;
+ getBezierValues(keyframeData, timeIn, valueIn, timeOut, valueOut);
+
+ if (!m_animCore->IsFirstKeyframe(kfHandle)) { // check tangent-in value
+ if (valueIn < minVal)
+ minVal = valueIn;
+ if (valueIn > maxVal)
+ maxVal = valueIn;
+ }
+
+ if (!m_animCore->IsLastKeyframe(kfHandle)) { // check tangent-out value
+ if (valueOut < minVal)
+ minVal = valueOut;
+ if (valueOut > maxVal)
+ maxVal = valueOut;
+ }
+ }
+ }
+ }
+ }
+
+ m_valScale = m_graphH / (maxVal - minVal);
+ m_graphY += minVal * m_valScale;
m_rowTimeline->update();
}
@@ -365,15 +401,13 @@ void RowTimelinePropertyGraph::pan(qreal dy)
void RowTimelinePropertyGraph::commitBezierEdit()
{
- // reset the changed keyframes and commit the changes, so the undo/redo works correctly
- QVector<std::pair<qt3dsdm::Qt3DSDMKeyframeHandle, TKeyframe>> changedKfs;
- for (auto data : qAsConst(m_currKeyframeData)) {
- changedKfs.append({data.first, m_animCore->GetKeyframeData(data.first)});
- m_animCore->SetKeyframeData(data.first, data.second);
- }
+ // reset the moved keyframe and commit the change, so the undo/redo works correctly
+ // Mahmoud_TODO: improve this (using Updatable editor?)
+ TKeyframe movedKeyframe = m_animCore->GetKeyframeData(m_currKeyframeData.first);
+ m_animCore->SetKeyframeData(m_currKeyframeData.first, m_currKeyframeData.second);
Q3DStudio::SCOPED_DOCUMENT_EDITOR(*g_StudioApp.GetCore()->GetDoc(), tr("Edit Bezier curve"))
- ->setBezierKeyframeValues(changedKfs);
+ ->setBezierKeyframeValue(m_currKeyframeData.first, movedKeyframe);
}
void RowTimelinePropertyGraph::setExpandHeight(int h)
diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h
index 5c3f1a71..93984fd3 100644
--- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h
+++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTimelinePropertyGraph.h
@@ -68,8 +68,7 @@ private:
BezierControlType type = BezierControlType::None) const;
QPointF getKeyframePosition(float time, float value) const;
- Qt3DSDMTimelineKeyframe::TKeyframeHandleList m_currKeyframeHandles;
- QVector<std::pair<qt3dsdm::Qt3DSDMKeyframeHandle, qt3dsdm::TKeyframe>> m_currKeyframeData;
+ std::pair<qt3dsdm::Qt3DSDMKeyframeHandle, qt3dsdm::TKeyframe> m_currKeyframeData;
RowTimeline *m_rowTimeline = nullptr;
ITimelineItemProperty *m_propBinding = nullptr;
qt3dsdm::IAnimationCore *m_animCore = nullptr;
diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
index f4159769..a86482fd 100644
--- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
+++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.cpp
@@ -48,6 +48,7 @@
#include "Qt3DSDMSlides.h"
#include "StudioUtils.h"
#include "TimelineToolbar.h"
+#include "HotKeys.h"
#include <QtGui/qpainter.h>
#include "QtGui/qtextcursor.h"
@@ -331,15 +332,31 @@ void RowTree::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, Q
else if (m_actionStates & ActionState::ComponentAction) // component has action
painter->drawPixmap(0, 0, hiResIcons ? pixCompAction2x : pixCompAction);
} else { // property row
- if (m_propGraphExpanded
- && m_PropBinding->animationType() == qt3dsdm::EAnimationTypeBezier) {
- const int PROP_GRAPH_CONTROLS_Y = int(TimelineConstants::ROW_H * 1.5);
- m_rectMaximizePropGraph.setRect(rightDividerX() - 16 * 1.1, PROP_GRAPH_CONTROLS_Y,
- ICON_SIZE, ICON_SIZE);
- m_rectFitPropGraph.setRect(rightDividerX() - 16 * 2.2, PROP_GRAPH_CONTROLS_Y,
- ICON_SIZE, ICON_SIZE);
- painter->drawPixmap(m_rectMaximizePropGraph, pixShy);
- painter->drawPixmap(m_rectFitPropGraph, pixShy);
+ if (m_propGraphExpanded) {
+ // draw maximize, fit graph buttons
+ if (m_PropBinding->animationType() == qt3dsdm::EAnimationTypeBezier) {
+ const int PROP_GRAPH_CONTROLS_Y = int(TimelineConstants::ROW_H * 1.5);
+ m_rectMaximizePropGraph.setRect(rightDividerX() - 16 * 1.1, PROP_GRAPH_CONTROLS_Y,
+ ICON_SIZE, ICON_SIZE);
+ m_rectFitPropGraph.setRect(rightDividerX() - 16 * 2.2, PROP_GRAPH_CONTROLS_Y,
+ ICON_SIZE, ICON_SIZE);
+ painter->drawPixmap(m_rectMaximizePropGraph, pixShy);
+ painter->drawPixmap(m_rectFitPropGraph, pixShy);
+ }
+
+ // draw channel selection buttons
+ const QString channelNames = m_rowTimeline->isColorProperty() ? QStringLiteral("rgba")
+ : QStringLiteral("xyzw");
+ for (int i = 0; i < m_rectChannels.size(); ++i) {
+ if (m_activeChannels[i])
+ painter->fillRect(m_rectChannels[i], CStudioPreferences::selectionColor());
+
+ painter->setPen(CStudioPreferences::studioColor3());
+ painter->drawRect(m_rectChannels[i]);
+
+ painter->setPen(CStudioPreferences::textColor());
+ painter->drawText(m_rectChannels[i].topLeft() + QPointF(5, 12), channelNames.at(i));
+ }
}
}
@@ -572,6 +589,18 @@ void RowTree::setPropBinding(ITimelineItemProperty *binding)
{
m_PropBinding = binding;
+ m_rectChannels.resize(m_PropBinding->GetChannelCount());
+ m_activeChannels.resize(m_PropBinding->GetChannelCount());
+
+ // For bezier animation select first channel (ie x) only by default, else select all channels
+ if (m_PropBinding->animationType() == qt3dsdm::EAnimationTypeBezier)
+ m_activeChannels[0] = true;
+ else
+ std::fill(m_activeChannels.begin(), m_activeChannels.end(), true);
+
+ for (int i = 0; i < m_rectChannels.size(); ++i)
+ m_rectChannels[i].setRect(22, TimelineConstants::ROW_H * (i+1), 16, 16);
+
if (parentRow()->expanded())
setRowVisible(true);
@@ -997,13 +1026,36 @@ TreeControlType RowTree::getClickedControl(const QPointF &scenePos)
}
if (isProperty()) {
- if (m_rectFitPropGraph.contains(p)) {
+ if (m_rectFitPropGraph.contains(p)) { // toggle fit graph
m_rowTimeline->propertyGraph()->fitGraph();
- } else if (m_rectMaximizePropGraph.contains(p)) {
+ } else if (m_rectMaximizePropGraph.contains(p)) { // toggle maximize graph
m_propGraphHeight = m_propGraphHeight == TimelineConstants::ROW_GRAPH_H
? TimelineConstants::ROW_GRAPH_H_MAX : TimelineConstants::ROW_GRAPH_H;
m_rowTimeline->propertyGraph()->setExpandHeight(m_propGraphHeight);
animateExpand(ExpandState::Expanded);
+ } else {
+ auto it = std::find_if(m_rectChannels.begin(), m_rectChannels.end(),
+ [&p](const QRect &r){ return r.contains(p); });
+
+ if (it != m_rectChannels.end()) { // clicked a channel button
+ bool ctrlDown = CHotKeys::isCtrlDown();
+ int chIdx = int(it->y() / TimelineConstants::ROW_H) - 1;
+ int numSelectedChannel = std::count(m_activeChannels.begin(),
+ m_activeChannels.end(), true);
+ bool isSingleSelected = numSelectedChannel == 1 && m_activeChannels[chIdx];
+ bool isMultiSelected = numSelectedChannel > 1 && m_activeChannels[chIdx];
+ if (!isSingleSelected && !(isMultiSelected && !ctrlDown))
+ m_activeChannels[chIdx] ^= 1;
+
+ if (!ctrlDown) {
+ for (int i = 0; i < m_activeChannels.size(); ++i) {
+ if (i != chIdx)
+ m_activeChannels[i] = false;
+ }
+ }
+ m_rowTimeline->propertyGraph()->fitGraph();
+ update();
+ }
}
}
@@ -1346,6 +1398,12 @@ bool RowTree::propertyExpanded() const
void RowTree::togglePropertyExpanded(const QPointF &scenePos)
{
QPoint p = mapFromScene(scenePos).toPoint();
+
+ for (int i = 0; i < m_rectChannels.size(); ++i) {
+ if (m_rectChannels[i].contains(p))
+ return; // mouse over a channel button
+ }
+
if (!m_rectFitPropGraph.contains(p) && !m_rectMaximizePropGraph.contains(p))
setPropertyExpanded(!m_propGraphExpanded);
}
@@ -1376,3 +1434,7 @@ void RowTree::showDataInputSelector(const QString &propertyname, const QPoint &p
pos);
}
+bool RowTree::channelActive(int channelIndex) const
+{
+ return m_activeChannels[channelIndex];
+}
diff --git a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h
index d82eada1..0e467e69 100644
--- a/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h
+++ b/src/Authoring/Qt3DStudio/Palettes/TimelineGraphicsView/ui/RowTree.h
@@ -156,6 +156,7 @@ public:
int rightDividerX() const;
int clipX() const;
qt3dsdm::Qt3DSDMInstanceHandle instance() const;
+ bool channelActive(int channelIndex) const;
protected:
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
@@ -216,6 +217,9 @@ private:
QRect m_rectType;
QRect m_rectMaximizePropGraph;
QRect m_rectFitPropGraph;
+ QVector<QRect> m_rectChannels;
+ QVector<bool> m_activeChannels;
+
QParallelAnimationGroup m_expandAnimation;
QPropertyAnimation *m_expandHeightAnimation;