From fac423880b5682f9fa36c28c2fbb78ef9a811f77 Mon Sep 17 00:00:00 2001 From: Elliu <elliu@hashi.re> Date: Wed, 2 Feb 2022 21:49:38 +0100 Subject: [PATCH] Working drag-and-drop timing bars on audio view Except for the starting line bar --- src/Lib/Ass/Line.cc | 6 + src/Lib/Ass/Line.hh | 2 + src/Lib/Ass/Syl.cc | 6 + src/Lib/Ass/Syl.hh | 2 + .../AudioVisualizer/TimingLine.cc | 124 +++++++++++++++--- .../AudioVisualizer/TimingLine.hh | 12 ++ .../AudioVisualizer/TimingSeparator.cc | 26 +++- .../AudioVisualizer/TimingSeparator.hh | 14 +- .../AudioVisualizer/TimingSyl.cc | 7 + .../AudioVisualizer/TimingSyl.hh | 3 + 10 files changed, 184 insertions(+), 18 deletions(-) diff --git a/src/Lib/Ass/Line.cc b/src/Lib/Ass/Line.cc index 71eafe81..27a2c35e 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 f24b2e9e..a5fffb0d 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 2c5a3d21..91c49b84 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 e112eef3..7c603cea 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 e4316254..26f920c1 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 ea7c7f86..a6116316 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 e8811d4d..cc0ac33f 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 61fdd95b..4d90df97 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 548324fa..291804cb 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 fcf74aea..26a46ae5 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); }; } -- GitLab