From fb459e3680f507196160d97c34d348caa36e5f32 Mon Sep 17 00:00:00 2001 From: Igor Korsukov <igor.korsukov@gmail.com> Date: Tue, 14 May 2024 12:07:41 +0300 Subject: [PATCH] [AU4] added frame start time and end time to timeline context --- .../ProjectScene/clipsview/Timeline.qml | 17 +++- .../view/clipsview/clipslistmodel.cpp | 2 +- .../view/clipsview/timelinecontext.cpp | 94 +++++++++++++------ .../view/clipsview/timelinecontext.h | 56 +++++++---- 4 files changed, 120 insertions(+), 49 deletions(-) diff --git a/au4/src/projectscene/qml/Audacity/ProjectScene/clipsview/Timeline.qml b/au4/src/projectscene/qml/Audacity/ProjectScene/clipsview/Timeline.qml index a041976f24..c5ccdb2659 100644 --- a/au4/src/projectscene/qml/Audacity/ProjectScene/clipsview/Timeline.qml +++ b/au4/src/projectscene/qml/Audacity/ProjectScene/clipsview/Timeline.qml @@ -13,6 +13,18 @@ Rectangle { height: 76 color: ui.theme.backgroundPrimaryColor + //! NOTE This element must be the same width as the track wave visible area. + //! If this is different, than appropriate changes must be made. + onWidthChanged: { + timelineContext.onResizeFrameWidth(root.width) + } + + Component.onCompleted: { + timelineContext.init(root.width) + } + + //! ~~~ TimelineContext ~~~ + //! NOTE See comment in TimelineContext (.h) function onWheel(y) { timelineContext.onWheel(y) } @@ -28,11 +40,14 @@ Rectangle { TimelineContext { id: timelineContext } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~ StyledTextLabel { anchors.fill: parent anchors.leftMargin: 16 - text: "zoom: " + timelineContext.zoom + ", offset: " + timelineContext.offset + text: "zoom: " + timelineContext.zoom + + ", frame start time: " + timelineContext.frameStartTime + + ", end time: " + timelineContext.frameEndTime } SeparatorLine { anchors.bottom: parent.bottom } diff --git a/au4/src/projectscene/view/clipsview/clipslistmodel.cpp b/au4/src/projectscene/view/clipsview/clipslistmodel.cpp index 8b2d3512c1..dabc1f7e3d 100644 --- a/au4/src/projectscene/view/clipsview/clipslistmodel.cpp +++ b/au4/src/projectscene/view/clipsview/clipslistmodel.cpp @@ -25,7 +25,7 @@ void ClipsListModel::load() if (m_context) { connect(m_context, &TimelineContext::zoomChanged, this, &ClipsListModel::onTimelineContextValuesChanged); - connect(m_context, &TimelineContext::offsetChanged, this, &ClipsListModel::onTimelineContextValuesChanged); + connect(m_context, &TimelineContext::frameTimeChanged, this, &ClipsListModel::onTimelineContextValuesChanged); } beginResetModel(); diff --git a/au4/src/projectscene/view/clipsview/timelinecontext.cpp b/au4/src/projectscene/view/clipsview/timelinecontext.cpp index 28e6e0bb9a..536632b4e6 100644 --- a/au4/src/projectscene/view/clipsview/timelinecontext.cpp +++ b/au4/src/projectscene/view/clipsview/timelinecontext.cpp @@ -8,18 +8,30 @@ static constexpr double ZOOM_MIN = 0.1; -TimelineContext::TimelineContext(QQuickItem* parent) - : QQuickItem(parent) +TimelineContext::TimelineContext(QObject* parent) + : QObject(parent) { } +void TimelineContext::init(double frameWidth) +{ + m_zoom = 2.0;//{ 44100.0 / 512.0 }; + emit zoomChanged(); + + m_frameStartTime = 0.0; + emit frameStartTimeChanged(); + m_frameEndTime = positionToTime(frameWidth); + emit frameEndTimeChanged(); + emit frameTimeChanged(); +} + void TimelineContext::onWheel(double y) { Qt::KeyboardModifiers modifiers = QApplication::keyboardModifiers(); if (modifiers.testFlag(Qt::ControlModifier)) { changeZoom(y < 0 ? -1 : 1); } else if (modifiers.testFlag(Qt::ShiftModifier)) { - changeOffset(y < 0 ? -1 : 1); + shiftFrameTime(y < 0 ? -1 : 1); } } @@ -38,10 +50,21 @@ void TimelineContext::changeZoom(int direction) setZoom(_zoom); } -void TimelineContext::changeOffset(int direction) +void TimelineContext::onResizeFrameWidth(double frameWidth) { - double step = 10; - setOffset(offset() + (step * direction)); + setFrameEndTime(m_frameStartTime + positionToTime(frameWidth)); + emit frameTimeChanged(); +} + +void TimelineContext::shiftFrameTime(int direction) +{ + double step = 10.0; + double shift = step * direction; + + setFrameStartTime(m_frameStartTime + shift); + setFrameEndTime(m_frameEndTime + shift); + + emit frameTimeChanged(); } void TimelineContext::onSelection(double x1, double x2) @@ -65,35 +88,16 @@ void TimelineContext::onSelectionTime(double startTime, double endTime) setSelectionActive(!muse::is_zero(startTime) && !muse::is_zero(endTime)); } -qint64 TimelineContext::timeToPosition(double time) const -{ - double t = 0.5 + m_zoom * (time - m_offset); - if (t < INT64_MIN) { - return INT64_MIN; - } - if (t > INT64_MAX) { - return INT64_MAX; - } - t = floor(t); - return static_cast<qint64>(t); -} - -double TimelineContext::positionToTime(qint64 position) const -{ - return m_offset + position / m_zoom; -} - -double TimelineContext::offset() const +double TimelineContext::timeToPosition(double time) const { - return m_offset; + double p = 0.5 + m_zoom * (time - m_frameStartTime); + p = std::floor(p); + return p; } -void TimelineContext::setOffset(double newOffset) +double TimelineContext::positionToTime(double position) const { - if (m_offset != newOffset) { - m_offset = newOffset; - emit offsetChanged(); - } + return m_frameStartTime + position / m_zoom; } double TimelineContext::zoom() const @@ -148,3 +152,31 @@ void TimelineContext::setSelectionActive(bool newSelectionActive) m_selectionActive = newSelectionActive; emit selectionActiveChanged(); } + +double TimelineContext::frameStartTime() const +{ + return m_frameStartTime; +} + +void TimelineContext::setFrameStartTime(double newFrameStartTime) +{ + if (qFuzzyCompare(m_frameStartTime, newFrameStartTime)) { + return; + } + m_frameStartTime = newFrameStartTime; + emit frameStartTimeChanged(); +} + +double TimelineContext::frameEndTime() const +{ + return m_frameEndTime; +} + +void TimelineContext::setFrameEndTime(double newFrameEndTime) +{ + if (qFuzzyCompare(m_frameEndTime, newFrameEndTime)) { + return; + } + m_frameEndTime = newFrameEndTime; + emit frameEndTimeChanged(); +} diff --git a/au4/src/projectscene/view/clipsview/timelinecontext.h b/au4/src/projectscene/view/clipsview/timelinecontext.h index 0cbc407c02..76bb2c1023 100644 --- a/au4/src/projectscene/view/clipsview/timelinecontext.h +++ b/au4/src/projectscene/view/clipsview/timelinecontext.h @@ -1,12 +1,23 @@ #pragma once -#include <QQuickItem> +#include <QObject> -class TimelineContext : public QQuickItem +//! NOTE This class does two things: +//! 1. This is a context that is passed to other classes +//! 2. This is a controller that interprets mouse and view resize events into context values +//! +//! If this class becomes more complex, +//! or we notice that its "controller" methods are being called in unexpected places, +//! then we should split it into two separate classes. + +class TimelineContext : public QObject { Q_OBJECT - Q_PROPERTY(double offset READ offset WRITE setOffset NOTIFY offsetChanged FINAL) + // 0 sec visible frame end + // | ~~~~~ ~~~~ ~~~| + Q_PROPERTY(double frameStartTime READ frameStartTime NOTIFY frameStartTimeChanged FINAL) + Q_PROPERTY(double frameEndTime READ frameEndTime NOTIFY frameEndTimeChanged FINAL) Q_PROPERTY(double zoom READ zoom WRITE setZoom NOTIFY zoomChanged FINAL) Q_PROPERTY(double selectionStartTime READ selectionStartTime NOTIFY selectionStartTimeChanged FINAL) @@ -15,17 +26,11 @@ class TimelineContext : public QQuickItem public: - TimelineContext(QQuickItem* parent = nullptr); - - Q_INVOKABLE void onWheel(double y); - Q_INVOKABLE void onSelection(double x1, double x2); - Q_INVOKABLE void resetSelection(); + TimelineContext(QObject* parent = nullptr); - Q_INVOKABLE qint64 timeToPosition(double time) const; - Q_INVOKABLE double positionToTime(qint64 position) const; + double frameStartTime() const; + double frameEndTime() const; - double offset() const; - void setOffset(double newOffset); double zoom() const; void setZoom(double zoom); @@ -35,9 +40,23 @@ public: void setSelectionEndTime(double time); bool selectionActive() const; + Q_INVOKABLE void init(double frameWidth); + + Q_INVOKABLE void onResizeFrameWidth(double frameWidth); + Q_INVOKABLE void onWheel(double y); + + Q_INVOKABLE void onSelection(double x1, double x2); + Q_INVOKABLE void resetSelection(); + + Q_INVOKABLE double timeToPosition(double time) const; + Q_INVOKABLE double positionToTime(double position) const; + signals: - void offsetChanged(); + void frameStartTimeChanged(); + void frameEndTimeChanged(); + void frameTimeChanged(); // any or both together + void zoomChanged(); void selectionStartTimeChanged(); @@ -46,15 +65,20 @@ signals: private: + void shiftFrameTime(int direction); + void setFrameStartTime(double newFrameStartTime); + void setFrameEndTime(double newFrameEndTime); + void changeZoom(int direction); - void changeOffset(int direction); void onSelectionTime(double t1, double t2); void updateSelectionActive(); void setSelectionActive(bool newSelectionActive); - double m_offset = 0.0; - double m_zoom = 2.0;//{ 44100.0 / 512.0 }; + double m_frameStartTime = 0.0; + double m_frameEndTime = 0.0; + + double m_zoom = 1.0; // see init double m_selecitonStartTime = 0.0; double m_selectionEndTime = 0.0; -- GitLab