diff --git a/src/Lib/Ass/Line.cc b/src/Lib/Ass/Line.cc index 71eafe81220b7297af8db8067a22496d6e7418c8..27a2c35ed8aaacadba6fe62504d6fdcc4b24faed 100644 --- a/src/Lib/Ass/Line.cc +++ b/src/Lib/Ass/Line.cc @@ -129,6 +129,12 @@ Line::getContent() const noexcept return content; } +QVector<Syl> * +Line::getContentPtr() noexcept +{ + return &content; +} + bool Line::getIsComment() const noexcept { diff --git a/src/Lib/Ass/Line.hh b/src/Lib/Ass/Line.hh index f24b2e9e48005a850d7fe2c429a5bdc015ff4276..a5fffb0d67e4398337dab433bdf8eddbce7fde28 100644 --- a/src/Lib/Ass/Line.hh +++ b/src/Lib/Ass/Line.hh @@ -44,6 +44,8 @@ public: StyleWeakPtr getStyle() const noexcept; const QVector<Syl> &getContent() const noexcept; + QVector<Syl> *getContentPtr() noexcept; // FIXME: remove me + quint64 getStart() const noexcept; quint64 getEnd() const noexcept; QString getContentAsText() const noexcept; diff --git a/src/Lib/Ass/Syl.cc b/src/Lib/Ass/Syl.cc index 2c5a3d217a8d5a86ceee4d5ee0de88427a2db40b..91c49b843479888ad66aeb04cd0b76daa3c3d434 100644 --- a/src/Lib/Ass/Syl.cc +++ b/src/Lib/Ass/Syl.cc @@ -41,3 +41,9 @@ Syl::getDuration() const noexcept { return duration; } + +void +Syl::setDuration(quint64 x) noexcept +{ + duration = x; +} diff --git a/src/Lib/Ass/Syl.hh b/src/Lib/Ass/Syl.hh index e112eef3a10a00c59cfad1eea6fc60b24d1b2e0d..7c603cea14e60d53b041e912a53ade1dd06aa6dd 100644 --- a/src/Lib/Ass/Syl.hh +++ b/src/Lib/Ass/Syl.hh @@ -31,6 +31,8 @@ public: QString getContent() const noexcept; quint64 getDuration() const noexcept; + void setDuration(quint64) noexcept; + private: static quint64 getDurationFromString(const QString &) noexcept; }; diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingLine.cc b/src/UI/DocumentViews/AudioVisualizer/TimingLine.cc index e43162541975ad10c17183969667708401dfd0c1..26f920c1ff66f86efadcc5353265aa08f80c8a52 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingLine.cc +++ b/src/UI/DocumentViews/AudioVisualizer/TimingLine.cc @@ -4,8 +4,6 @@ #include <QGraphicsScene> #include "TimingUtils.hh" -#include "TimingSyl.hh" -#include "TimingSeparator.hh" using namespace Vivy; @@ -14,27 +12,42 @@ TimingLine::TimingLine(Ass::Line *lineptr, QGraphicsItem *parent) , line(*lineptr) { setPos(TimingUtils::posFromMs(int(line.getStart()) * 10), TimingUtils::axisHeight()); - int currentTime = 0; + originalX = pos().x(); + originalY = pos().y(); + int currentTime = 0; + int endSyl = 0; + int i; + + TimingSeparator *timingSeparatorStart = + new TimingSeparator(currentTime, 0, TimingSeparator::SeparatorStyle::Start, this); + seps.append(timingSeparatorStart); + connect(timingSeparatorStart, &TimingSeparator::positionChanged, this, + &TimingLine::timingSeparatorHasChanged); + QVector<Ass::Syl> syls = line.getContent(); - for (int i = 0; i < syls.size(); ++i) { - int endSyl = currentTime + 10 * int(syls.at(i).getDuration()); + for (i = 0; i < syls.size(); ++i) { + endSyl = currentTime + 10 * int(syls.at(i).getDuration()); TimingSyl *timingSyl = new TimingSyl(syls.at(i), currentTime, this); + timingSyls.append(timingSyl); // TODO: Here create the TimingSeparator and connect - TimingSeparator *timingSeparatorStart = - new TimingSeparator(currentTime, - i != 0 ? TimingSeparator::SeparatorStyle::Middle - : TimingSeparator::SeparatorStyle::Start, - this); - TimingSeparator *timingSeparatorEnd = - new TimingSeparator(i != syls.size() - 1 ? endSyl : int(10 * line.getDuration()), - i != syls.size() - 1 ? TimingSeparator::SeparatorStyle::Middle - : TimingSeparator::SeparatorStyle::End, - this); + if (i != 0) { + TimingSeparator *timingSeparator = + new TimingSeparator(currentTime, i, TimingSeparator::SeparatorStyle::Middle, this); + seps.append(timingSeparator); + connect(timingSeparator, &TimingSeparator::positionChanged, this, + &TimingLine::timingSeparatorHasChanged); + } currentTime = endSyl; } + + TimingSeparator *timingSeparatorEnd = + new TimingSeparator(currentTime, i, TimingSeparator::SeparatorStyle::End, this); + seps.append(timingSeparatorEnd); + connect(timingSeparatorEnd, &TimingSeparator::positionChanged, this, + &TimingLine::timingSeparatorHasChanged); } QRectF @@ -52,3 +65,84 @@ TimingLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWi TimingUtils::audioHeight()), QColor(0, 255, 255, 50)); } + +void +TimingLine::timingSeparatorHasChanged(int sylIndex, qreal x) +{ +} + +qreal +TimingLine::requestMove(int sepIndex, qreal x) +{ + QRectF sceneRect = mapRectFromScene(scene()->sceneRect()); + QVector<Ass::Syl> *syls = line.getContentPtr(); + + qreal ret = x; + qreal mini, maxi; + + if (sepIndex <= 0) { + prepareGeometryChange(); + + mini = sceneRect.left(); + maxi = sepIndex < syls->size() - 1 ? timingSyls[sepIndex + 1]->pos().x() + : TimingUtils::posFromMs(int(line.getDuration()) * 10); + + if (ret < mini) + ret = mini; + if (ret > maxi) + ret = maxi; + + quint64 dur1 = quint64(TimingUtils::msFromPos(int(seps[1]->pos().x() - ret)) / 10); + (*syls)[0].setDuration(dur1); + timingSyls[0]->setLen(dur1); + setPos(originalX + ret, originalY); + line.setStart(line.getStart() + + quint64(TimingUtils::msFromPos(int(originalX) + int(ret) / 10))); + } + + else if (sepIndex >= syls->size()) { + prepareGeometryChange(); + + mini = timingSyls[sepIndex - 1]->pos().x(); + maxi = sceneRect.right(); + + if (ret < mini) + ret = mini; + if (ret > maxi) + ret = maxi; + + quint64 dur2 = + quint64(TimingUtils::msFromPos(int(ret - timingSyls[sepIndex - 1]->pos().x())) / 10); + (*syls)[sepIndex - 1].setDuration(dur2); + timingSyls[sepIndex - 1]->setLen(dur2); + line.setEnd(line.getStart() + quint64(TimingUtils::msFromPos(int(ret)) / 10)); + } + + else { + mini = timingSyls[sepIndex - 1]->pos().x(); + maxi = sepIndex < syls->size() - 1 ? timingSyls[sepIndex + 1]->pos().x() + : TimingUtils::posFromMs(int(line.getDuration() * 10)); + + if (ret < mini) + ret = mini; + if (ret > maxi) + ret = maxi; + + quint64 sumDur = (*syls)[sepIndex].getDuration() + (*syls)[sepIndex - 1].getDuration(); + quint64 dur1 = quint64( + TimingUtils::msFromPos(int(ret) - int(timingSyls[sepIndex - 1]->pos().x())) / 10); + if (dur1 > sumDur) { + dur1 = sumDur; + } + quint64 dur2 = sumDur - dur1; + + (*syls)[sepIndex - 1].setDuration(dur1); + (*syls)[sepIndex].setDuration(dur2); + + timingSyls[sepIndex - 1]->setLen(dur1); + timingSyls[sepIndex]->setPos(ret, 0); + timingSyls[sepIndex]->setLen(dur2); + } + + return ret; +} diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingLine.hh b/src/UI/DocumentViews/AudioVisualizer/TimingLine.hh index ea7c7f86f82168e20cd2e003889339dd919815eb..a611631624eba593bc6d4901e6f2e6a20184c8b7 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingLine.hh +++ b/src/UI/DocumentViews/AudioVisualizer/TimingLine.hh @@ -3,6 +3,8 @@ #include <QGraphicsObject> #include "../../../Lib/Ass/Ass.hh" +#include "TimingSeparator.hh" +#include "TimingSyl.hh" namespace Vivy { @@ -16,6 +18,16 @@ public: private: Ass::Line line; + QVector<TimingSeparator *> seps; + QVector<TimingSyl *> timingSyls; + int originalX; + int originalY; + +public: + qreal requestMove(int, qreal); + +public slots: + void timingSeparatorHasChanged(int, qreal); }; } diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.cc b/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.cc index e8811d4dedb3b587a7c013d204446d3aaa676d4e..cc0ac33f8ba902520187b962970f5e7632ac7ce4 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.cc +++ b/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.cc @@ -2,17 +2,25 @@ #include <QPainter> #include <QGraphicsScene> +#include <QDrag> #include "TimingUtils.hh" +#include "TimingLine.hh" using namespace Vivy; -TimingSeparator::TimingSeparator(int time, SeparatorStyle style_, QGraphicsItem *parent) +TimingSeparator::TimingSeparator(int time, int index, SeparatorStyle style_, TimingLine *parent) : QGraphicsObject(parent) , style(style_) + , sepIndex(index) + , parentTimingLine(parent) { setPos(TimingUtils::posFromMs(time), 0); + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemSendsGeometryChanges); + setAcceptHoverEvents(true); + setCursor(Qt::PointingHandCursor); + switch (style) { case SeparatorStyle::Start: pen = QPen(QColor(0, 0, 255)); break; case SeparatorStyle::Middle: pen = QPen(QColor(180, 0, 180)); break; @@ -54,3 +62,19 @@ TimingSeparator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option break; } } + +QVariant +TimingSeparator::itemChange(GraphicsItemChange change, const QVariant &value) noexcept +{ + if (change == ItemPositionChange) { + qreal destination = value.toPointF().x(); + destination = parentTimingLine->requestMove(sepIndex, destination); + + if (style == SeparatorStyle::Start) + destination = 0; + + emit positionChanged(sepIndex, destination); + return QPointF(destination, 0); + } + return QGraphicsObject::itemChange(change, value); +} diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.hh b/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.hh index 61fdd95bc16e3b1d738a652bdd97dbc5140dbfe1..4d90df97102f750b3419ea1ebe5b93e595b2b7ea 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.hh +++ b/src/UI/DocumentViews/AudioVisualizer/TimingSeparator.hh @@ -1,17 +1,19 @@ #pragma once #include <QGraphicsObject> +#include <QGraphicsSceneDragDropEvent> namespace Vivy { +class TimingLine; + class TimingSeparator final : public QGraphicsObject { Q_OBJECT public: enum class SeparatorStyle { Start, Middle, End }; public: - explicit TimingSeparator(int, SeparatorStyle style = SeparatorStyle::Middle, - QGraphicsItem *parent = nullptr); + explicit TimingSeparator(int, int, SeparatorStyle, TimingLine *); QRectF boundingRect() const override; void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; @@ -20,6 +22,14 @@ private: SeparatorStyle style; int widthPaw = 5; QPen pen; + int sepIndex; + TimingLine *parentTimingLine; + +signals: + void positionChanged(int, qreal); + +protected: + QVariant itemChange(GraphicsItemChange change, const QVariant &value) noexcept override; }; } diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingSyl.cc b/src/UI/DocumentViews/AudioVisualizer/TimingSyl.cc index 548324fa910c9570cadcaac178faf2142f416a49..291804cb62835b2ae501941ce449a35566e86ba8 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingSyl.cc +++ b/src/UI/DocumentViews/AudioVisualizer/TimingSyl.cc @@ -26,3 +26,10 @@ TimingSyl::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWid { painter->drawText(boundingRect(), Qt::AlignCenter, syl.getContent()); } + +void +TimingSyl::setLen(quint64 len) +{ + prepareGeometryChange(); + syl.setDuration(len); +} diff --git a/src/UI/DocumentViews/AudioVisualizer/TimingSyl.hh b/src/UI/DocumentViews/AudioVisualizer/TimingSyl.hh index fcf74aea60089e621e2b2347f52f286b5ad8213c..26a46ae56d4f6aa0c4e9dcbba9f2c5893f4bd9e3 100644 --- a/src/UI/DocumentViews/AudioVisualizer/TimingSyl.hh +++ b/src/UI/DocumentViews/AudioVisualizer/TimingSyl.hh @@ -16,6 +16,9 @@ public: private: Ass::Syl syl; + +public: + void setLen(quint64 len); }; }