summaryrefslogtreecommitdiffstats
path: root/src/Authoring/Studio/Palettes/Timeline
diff options
context:
space:
mode:
authorMauro Persano <mauro.persano@kdab.com>2017-12-12 21:19:18 -0200
committerAndras Mantia <andras@kdab.com>2017-12-20 10:56:48 +0000
commitdd78a8df86ff02e95b464e120faac8e83478ca4a (patch)
tree12a543ac642bb0376fa0c4ba8b5a1e3739eea620 /src/Authoring/Studio/Palettes/Timeline
parent07cce9cbd771fdf09781570e97032af8f0d1cdf1 (diff)
Add timeline tick marks
Port the tick mark drawing code in CTimeMeasure to a QML item Change-Id: I75410f9d95e9c8a9aed6bb451ea9f22fa38c476b Reviewed-by: Andras Mantia <andras@kdab.com>
Diffstat (limited to 'src/Authoring/Studio/Palettes/Timeline')
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.cpp207
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.h63
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/Timeline.qml226
-rw-r--r--src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp3
4 files changed, 402 insertions, 97 deletions
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.cpp b/src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.cpp
new file mode 100644
index 00000000..92b87390
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.cpp
@@ -0,0 +1,207 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "TimeMeasureItem.h"
+#include "CoreUtils.h"
+#include "StudioUtils.h"
+#include "StudioPreferences.h"
+
+#include <QPainter>
+
+TimeMeasureItem::TimeMeasureItem(QQuickItem *parent)
+ : QQuickPaintedItem(parent)
+{
+}
+
+TimeMeasureItem::~TimeMeasureItem()
+{
+}
+
+void TimeMeasureItem::paint(QPainter *painter)
+{
+ const double edgeMargin = 2;
+ const double largeHashOffset = 5;
+ const double mediumHashOffset = 6;
+ const double smallHashOffset = 3;
+
+ QPen pen(CStudioPreferences::GetRulerTickColor());
+ painter->setPen(pen);
+
+ long theLength = width();
+ long theHeight = height() - edgeMargin;
+
+ double theTotalMeasure = theLength / m_Ratio;
+
+ long theNumLargeHashes = (long)(theTotalMeasure / m_LargeHashInterval) + 1;
+
+ long theOffset = m_Offset - (m_Offset % ::dtol(m_LargeHashInterval));
+
+ for (long i = 0; i < theNumLargeHashes + 1; ++i) {
+ double theMeasure = m_LargeHashInterval * i + theOffset;
+
+ long thePos = ::TimeToPos(theMeasure - m_Offset, m_Ratio);
+
+ if (thePos > 0)
+ painter->drawLine(thePos, theHeight, thePos, theHeight - largeHashOffset);
+
+ DrawMeasureText(painter, thePos, long(theMeasure));
+
+ // sanity check
+ if (m_MediumHashInterval > 0) {
+ thePos = ::TimeToPos(theMeasure - m_Offset + m_MediumHashInterval, m_Ratio);
+ if (thePos > 0)
+ painter->drawLine(thePos, theHeight, thePos, theHeight - mediumHashOffset);
+
+ for (double theSmallInterval = 0; theSmallInterval < m_LargeHashInterval;
+ theSmallInterval += m_SmallHashInterval) {
+ thePos = ::TimeToPos(theMeasure - m_Offset + theSmallInterval, m_Ratio);
+
+ if (thePos > 0)
+ painter->drawLine(thePos, theHeight, thePos, theHeight - smallHashOffset);
+ }
+ } // if medium is valid
+ }
+
+ // Draw the top outline
+ painter->drawLine(0, theHeight, theLength, theHeight);
+}
+
+void TimeMeasureItem::setTimeRatio(double inTimeRatio)
+{
+ if (qFuzzyCompare(m_Ratio, inTimeRatio))
+ return;
+
+ m_Ratio = inTimeRatio;
+
+ double theTimePerPixel = (double)(1 / inTimeRatio);
+
+ // Only go through this if it has actually changed
+ if (theTimePerPixel != m_TimePerPixel) {
+ m_TimePerPixel = theTimePerPixel;
+
+ // Go through the possible hash settings and find the one that best suits the
+ // time per pixel.
+ double theMillisPerLargeHash = theTimePerPixel * 50;
+ if (theMillisPerLargeHash <= 100) // 100ms
+ theMillisPerLargeHash = 100;
+ else if (theMillisPerLargeHash <= 200) // 200ms
+ theMillisPerLargeHash = 200;
+ else if (theMillisPerLargeHash <= 500) // .5s
+ theMillisPerLargeHash = 500;
+ else if (theMillisPerLargeHash <= 1000) // 1s
+ theMillisPerLargeHash = 1000;
+ else if (theMillisPerLargeHash <= 2000) // 2s
+ theMillisPerLargeHash = 2000;
+ else if (theMillisPerLargeHash <= 5000) // 5s
+ theMillisPerLargeHash = 5000;
+ else if (theMillisPerLargeHash <= 10000) // 10s
+ theMillisPerLargeHash = 10000;
+ else if (theMillisPerLargeHash <= 20000) // 20s
+ theMillisPerLargeHash = 20000;
+ else if (theMillisPerLargeHash <= 30000) // 30s
+ theMillisPerLargeHash = 30000;
+ else if (theMillisPerLargeHash <= 60000) // 1m
+ theMillisPerLargeHash = 60000;
+ else if (theMillisPerLargeHash <= 120000) // 2m
+ theMillisPerLargeHash = 120000;
+ else if (theMillisPerLargeHash <= 300000) // 5m
+ theMillisPerLargeHash = 300000;
+ else if (theMillisPerLargeHash <= 600000) // 10m
+ theMillisPerLargeHash = 600000;
+ else if (theMillisPerLargeHash <= 1200000) // 20m
+ theMillisPerLargeHash = 1200000;
+ else if (theMillisPerLargeHash <= 1800000) // 30m
+ theMillisPerLargeHash = 1800000;
+ else if (theMillisPerLargeHash <= 3600000) // 1h
+ theMillisPerLargeHash = 3600000;
+ else
+ theMillisPerLargeHash = 7200000; // 2h
+
+ // Set the distances between the hashes
+ m_LargeHashInterval = theMillisPerLargeHash;
+ m_MediumHashInterval = theMillisPerLargeHash / 2;
+ m_SmallHashInterval = theMillisPerLargeHash / 10;
+
+ update();
+ }
+
+ emit timeRatioChanged(inTimeRatio);
+}
+
+double TimeMeasureItem::timeRatio() const
+{
+ return m_Ratio;
+}
+
+void TimeMeasureItem::DrawMeasureText(QPainter *painter, long inPosition, long inMeasure) const
+{
+ QString theTimeFormat(FormatTime(inMeasure));
+
+ // Offset the position by half the text size to center it over the hash.
+ QFontMetrics fm = painter->fontMetrics();
+ const auto textSize = fm.size(Qt::TextSingleLine, theTimeFormat);
+ inPosition -= ::dtol(textSize.width() / 2);
+
+ QRectF rect(0, 0, width(), height());
+ rect.translate(inPosition, -3);
+
+ painter->drawText(rect, Qt::AlignLeft | Qt::AlignVCenter, theTimeFormat);
+}
+
+QString TimeMeasureItem::FormatTime(long inTime) const
+{
+ long theHours = inTime / 3600000;
+ long theMinutes = inTime % 3600000 / 60000;
+ long theSeconds = inTime % 60000 / 1000;
+ long theMillis = inTime % 1000;
+
+ bool theHoursOnlyFlag = theHours != 0 && theMinutes == 0 && theSeconds == 0 && theMillis == 0;
+ bool theMinutesOnlyFlag =
+ !theHoursOnlyFlag && theMinutes != 0 && theSeconds == 0 && theMillis == 0;
+ bool theSecondsOnlyFlag = !theMinutesOnlyFlag && theMillis == 0;
+
+ QString theTime;
+ // If only hours are being displayed then format it as hours.
+ if (theHoursOnlyFlag) {
+ theTime = tr("%1h").arg(theHours);
+ }
+ // If only minutes are being displayed then format it as minutes.
+ else if (theMinutesOnlyFlag) {
+ theTime = tr("%1m").arg(theMinutes);
+ }
+ // If only seconds are being displayed then format as seconds
+ else if (theSecondsOnlyFlag) {
+ theTime = tr("%1s").arg(theSeconds);
+ }
+ // If the intervals are correct then this should only be tenths of seconds, so do that.
+ else {
+ theTime = tr("0.%1s").arg(theMillis / 100);
+ }
+
+ return theTime;
+}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.h b/src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.h
new file mode 100644
index 00000000..5304929d
--- /dev/null
+++ b/src/Authoring/Studio/Palettes/Timeline/TimeMeasureItem.h
@@ -0,0 +1,63 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** 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.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef TIMEMEASUREITEM_H
+#define TIMEMEASUREITEM_H
+
+#include <QQuickPaintedItem>
+
+class TimeMeasureItem : public QQuickPaintedItem
+{
+ Q_OBJECT
+ Q_PROPERTY(double timeRatio READ timeRatio WRITE setTimeRatio NOTIFY timeRatioChanged)
+
+public:
+ explicit TimeMeasureItem(QQuickItem *parent = nullptr);
+ ~TimeMeasureItem() override;
+
+ void paint(QPainter *painter) override;
+
+ double timeRatio() const;
+ void setTimeRatio(double timeRatio);
+
+Q_SIGNALS:
+ void timeRatioChanged(double timeRatio);
+
+private:
+ void DrawMeasureText(QPainter *painter, long inPosition, long inMeasure) const;
+ QString FormatTime(long inTime) const;
+
+ double m_SmallHashInterval = 0.0;
+ double m_MediumHashInterval = 0.0;
+ double m_LargeHashInterval = 0.0;
+ double m_Ratio = 0.0;
+ long m_Offset = 0;
+ double m_TimePerPixel = 0.0;
+};
+
+#endif // TIMEMEASUREITEM_H
diff --git a/src/Authoring/Studio/Palettes/Timeline/Timeline.qml b/src/Authoring/Studio/Palettes/Timeline/Timeline.qml
index 45db8df6..4dfb0b78 100644
--- a/src/Authoring/Studio/Palettes/Timeline/Timeline.qml
+++ b/src/Authoring/Studio/Palettes/Timeline/Timeline.qml
@@ -29,6 +29,7 @@
import QtQuick 2.8
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
+import Qt3DStudio 1.0
import "../controls"
Rectangle {
@@ -48,102 +49,117 @@ Rectangle {
spacing: 5
- ListView {
- id: browserList
+ ColumnLayout {
+ anchors.fill: parent
+ spacing: 0
Layout.minimumWidth: root.splitterPos
Layout.maximumWidth: root.splitterPos
- Layout.fillHeight: true
- Layout.minimumHeight: 80
- Layout.preferredHeight: count * 20
Layout.preferredWidth: root.width
- ScrollBar.vertical: scrollBar
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.preferredWidth: parent.width
+ Layout.preferredHeight: itemHeight
+ color: "transparent"
+ }
- model: _timelineView.objectModel
- boundsBehavior: Flickable.StopAtBounds
- clip: true
- currentIndex: _timelineView.selection
+ ListView {
+ id: browserList
+
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.minimumHeight: 80
+ Layout.preferredHeight: count * itemHeight
+ Layout.preferredWidth: root.width
+
+ ScrollBar.vertical: scrollBar
- delegate: Rectangle {
- id: delegateItem
+ model: _timelineView.objectModel
+ boundsBehavior: Flickable.StopAtBounds
+ clip: true
+ currentIndex: _timelineView.selection
+
+ delegate: Rectangle {
+ id: delegateItem
- width: parent.width
- height: model.parentExpanded ? itemHeight : 0
+ width: parent.width
+ height: model.parentExpanded ? itemHeight : 0
- color: model.selected ? _selectionColor : _studioColor2
- border.color: _backgroundColor
+ color: model.selected ? _selectionColor : _studioColor2
+ border.color: _backgroundColor
- visible: height > 0
+ visible: height > 0
- Behavior on height {
- NumberAnimation {
- duration: 100
- easing.type: Easing.OutQuad
+ Behavior on height {
+ NumberAnimation {
+ duration: 100
+ easing.type: Easing.OutQuad
+ }
}
- }
- MouseArea {
- id: delegateArea
+ MouseArea {
+ id: delegateArea
- anchors.fill: parent
- onClicked: _timelineView.select(model.index, mouse.modifiers)
- }
+ anchors.fill: parent
+ onClicked: _timelineView.select(model.index, mouse.modifiers)
+ }
- Row {
- id: row
+ Row {
+ id: row
- x: model.depth * 20
- anchors.verticalCenter: parent.verticalCenter
- height: itemHeight
- width: splitterPos - x
- spacing: 5
+ x: model.depth * 20
+ anchors.verticalCenter: parent.verticalCenter
+ height: itemHeight
+ width: splitterPos - x
+ spacing: 5
- Image {
- source: {
- if (!model.hasChildren)
+ Image {
+ source: {
+ if (!model.hasChildren)
return "";
- model.expanded ? _resDir + "arrow_down.png"
- : _resDir + "arrow.png";
- }
+ model.expanded ? _resDir + "arrow_down.png"
+ : _resDir + "arrow.png";
+ }
- MouseArea {
- anchors.fill: parent
- onClicked: model.expanded = !model.expanded
+ MouseArea {
+ anchors.fill: parent
+ onClicked: model.expanded = !model.expanded
+ }
}
- }
- Item {
- height: itemHeight
- width: typeIcon.width + name.width + 10
+ Item {
+ height: itemHeight
+ width: typeIcon.width + name.width + 10
- Row {
- spacing: 10
- Image {
- id: typeIcon
+ Row {
+ spacing: 10
+ Image {
+ id: typeIcon
- source: model.icon
- }
+ source: model.icon
+ }
- StyledLabel {
- id: name
- anchors.verticalCenter: typeIcon.verticalCenter
- color: model.textColor
- text: model.name
+ StyledLabel {
+ id: name
+ anchors.verticalCenter: typeIcon.verticalCenter
+ color: model.textColor
+ text: model.name
+ }
}
}
}
}
- }
- onCurrentIndexChanged: _timelineView.selection = currentIndex
+ onCurrentIndexChanged: _timelineView.selection = currentIndex
- Connections {
- target: _timelineView
- onSelectionChanged: {
- if (browserList.currentIndex !== _timelineView.selection)
+ Connections {
+ target: _timelineView
+ onSelectionChanged: {
+ if (browserList.currentIndex !== _timelineView.selection)
browserList.currentIndex = _timelineView.selection;
+ }
}
}
}
@@ -152,7 +168,7 @@ Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.minimumHeight: 80
- Layout.preferredHeight: timelineItemsList.count * 20
+ Layout.preferredHeight: (timelineItemsList.count + 1) * itemHeight
Layout.preferredWidth: root.width
contentHeight: height
@@ -163,50 +179,66 @@ Rectangle {
policy: ScrollBar.AlwaysOn
}
- ListView {
- id: timelineItemsList
-
+ ColumnLayout {
anchors.fill: parent
- ScrollBar.vertical: scrollBar
+ spacing: 0
- model: browserList.model
- boundsBehavior: Flickable.StopAtBounds
- clip: true
- currentIndex: browserList.currentIndex
+ TimeMeasureItem {
+ Layout.fillWidth: true
+ Layout.preferredWidth: parent.width
+ Layout.preferredHeight: itemHeight
+ timeRatio: 0.05
+ }
- delegate: Rectangle {
- id: timelineItemsDelegateItem
+ ListView {
+ id: timelineItemsList
- width: parent.width
- height: model.parentExpanded ? itemHeight : 0
+ Layout.fillWidth: true
+ Layout.fillHeight: true
+ Layout.preferredHeight: count * itemHeight
+ Layout.preferredWidth: root.width
- color: model.selected ? _selectionColor : "#404244"
- border.color: _backgroundColor
+ ScrollBar.vertical: scrollBar
- visible: height > 0
+ model: browserList.model
+ boundsBehavior: Flickable.StopAtBounds
+ clip: true
+ currentIndex: browserList.currentIndex
- MouseArea {
- id: timelineItemsDelegateArea
+ delegate: Rectangle {
+ id: timelineItemsDelegateItem
- anchors.fill: parent
- onClicked: _timelineView.select(model.index, mouse.modifiers)
- }
+ width: parent.width
+ height: model.parentExpanded ? itemHeight : 0
- TimelineItem {
- height: parent.height
- visible: timeInfo.endPosition > timeInfo.startPosition
+ color: model.selected ? _selectionColor : "#404244"
+ border.color: _backgroundColor
- timeInfo: model.timeInfo
- color: model.itemColor
- borderColor: root.color
- selected: model.selected
- selectionColor: model.selectedColor
- }
+ visible: height > 0
- Keyframes {
- anchors.verticalCenter: parent.verticalCenter
- keyframes: model.keyframes
+ MouseArea {
+ id: timelineItemsDelegateArea
+
+ anchors.fill: parent
+ onClicked: _timelineView.select(model.index, mouse.modifiers)
+ }
+
+ TimelineItem {
+ height: parent.height
+ visible: timeInfo.endPosition > timeInfo.startPosition
+
+ timeInfo: model.timeInfo
+ color: model.itemColor
+ borderColor: root.color
+ selected: model.selected
+ selectionColor: model.selectedColor
+ }
+
+ Keyframes {
+ anchors.verticalCenter: parent.verticalCenter
+ keyframes: model.keyframes
+ }
}
}
}
diff --git a/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp b/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp
index 10707e21..93d1a25b 100644
--- a/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp
+++ b/src/Authoring/Studio/Palettes/Timeline/TimelineView.cpp
@@ -37,6 +37,8 @@
#include "StudioPreferences.h"
#include "StudioUtils.h"
+#include "TimeMeasureItem.h"
+
#include "Qt3DSDMStudioSystem.h"
#include "Qt3DSDMSlides.h"
#include "Qt3DSDMHandles.h"
@@ -169,6 +171,7 @@ void TimelineView::initialize()
, tr("Creation of TimebarTimeInfo not allowed from QML"));
qmlRegisterUncreatableType<TimebarTimeInfo>("Qt3DStudio", 1, 0, "KeyframeInfo"
, tr("Creation of KeyframeInfo not allowed from QML"));
+ qmlRegisterType<TimeMeasureItem>("Qt3DStudio", 1, 0, "TimeMeasureItem");
engine()->addImportPath(qmlImportPath());
setSource(QUrl("qrc:/Palettes/Timeline/Timeline.qml"_L1));
}