Skip to content

Commit 86c40cc

Browse files
committed
Add RangeIndicatorSequence view for clips and synth pieces
Close #33
1 parent 277ee2b commit 86c40cc

16 files changed

Lines changed: 403 additions & 128 deletions

AGENTS.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ View-model bindings maintain explicit document-to-view and view-to-document maps
154154

155155
Use a recursive checkout, CMake 3.19+, Qt 6.10-compatible development packages, Ninja, and a C++20 compiler. During vcpkg installation, expose the Qt CMake directory through `QT_DIR`/`Qt6_DIR` and retain those variables for overlay ports.
156156

157-
Do not perform any build, test, run, or automatic formatting operations unless explicitly requested by the user.
157+
Do not perform any test, build, run, or automatic formatting operations unless explicitly requested by the user. Also do not include any of these operations in the plan unless explicitly requested by the user.
158158

159159
```sh
160160
git submodule update --init --recursive

src/plugins/synthvisualizer/internal/addon/SynthesisPieceTrackAddOn.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
#include <QAKQuick/quickactioncontext.h>
1313

14+
#include <ScopicFlowCore/RangeIndicatorInteractionController.h>
15+
1416
#include <coreplugin/ProjectWindowInterface.h>
1517

1618
#include <synth/ProjectSynthesisContext.h>
@@ -27,10 +29,15 @@ namespace SynthVisualizer::Internal {
2729

2830
SynthesisPieceTrackAddOn::~SynthesisPieceTrackAddOn() = default;
2931

30-
QAbstractItemModel *SynthesisPieceTrackAddOn::pieceModel() const {
32+
SynthesisPieceModel *SynthesisPieceTrackAddOn::pieceModel() const {
3133
return m_pieceModel;
3234
}
3335

36+
sflow::RangeIndicatorInteractionController *
37+
SynthesisPieceTrackAddOn::rangeIndicatorInteractionController() const {
38+
return m_rangeIndicatorInteractionController;
39+
}
40+
3441
void SynthesisPieceTrackAddOn::initialize() {
3542
auto windowInterface = windowHandle()->cast<Core::ProjectWindowInterface>();
3643
if (!windowInterface) {
@@ -43,6 +50,8 @@ namespace SynthVisualizer::Internal {
4350
qCWarning(lcSynthesisPieceTrackAddOn) << "The project synthesis context is unavailable";
4451
}
4552
m_pieceModel = new SynthesisPieceModel(synthesisContext, this);
53+
m_rangeIndicatorInteractionController =
54+
new sflow::RangeIndicatorInteractionController(this);
4655

4756
QQmlComponent component(
4857
Core::RuntimeInterface::qmlEngine(),

src/plugins/synthvisualizer/internal/addon/SynthesisPieceTrackAddOn.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,28 +6,33 @@
66

77
#include <CoreApi/windowinterface.h>
88

9-
class QAbstractItemModel;
9+
namespace sflow {
10+
class RangeIndicatorInteractionController;
11+
}
1012

1113
namespace SynthVisualizer::Internal {
1214

1315
class SynthesisPieceModel;
1416

1517
class SynthesisPieceTrackAddOn : public Core::WindowInterfaceAddOn {
1618
Q_OBJECT
17-
Q_PROPERTY(QAbstractItemModel *pieceModel READ pieceModel CONSTANT)
19+
Q_PROPERTY(SynthesisPieceModel *pieceModel READ pieceModel CONSTANT)
20+
Q_PROPERTY(sflow::RangeIndicatorInteractionController *rangeIndicatorInteractionController READ rangeIndicatorInteractionController CONSTANT)
1821

1922
public:
2023
explicit SynthesisPieceTrackAddOn(QObject *parent = nullptr);
2124
~SynthesisPieceTrackAddOn() override;
2225

23-
QAbstractItemModel *pieceModel() const;
26+
SynthesisPieceModel *pieceModel() const;
27+
sflow::RangeIndicatorInteractionController *rangeIndicatorInteractionController() const;
2428

2529
void initialize() override;
2630
void extensionsInitialized() override;
2731
bool delayedInitialize() override;
2832

2933
private:
3034
SynthesisPieceModel *m_pieceModel{};
35+
sflow::RangeIndicatorInteractionController *m_rangeIndicatorInteractionController{};
3136
};
3237

3338
}

src/plugins/synthvisualizer/internal/model/SynthesisPieceModel.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,14 @@
77
#include <utility>
88

99
#include <QFileInfo>
10+
#include <QSet>
1011
#include <QVariant>
1112

13+
#include <SVSCraftCore/SVSCraftNamespace.h>
14+
15+
#include <ScopicFlowCore/RangeIndicatorViewModel.h>
16+
#include <ScopicFlowCore/RangeSequenceViewModel.h>
17+
1218
#include <dspxmodelORM/SingingClip.h>
1319

1420
#include <coreplugin/ProjectWindowInterface.h>
@@ -20,6 +26,8 @@ namespace SynthVisualizer::Internal {
2026

2127
SynthesisPieceModel::SynthesisPieceModel(QObject *parent)
2228
: QAbstractListModel(parent) {
29+
m_rangeIndicatorSequenceViewModel =
30+
new sflow::RangeSequenceViewModel(this, "position", "length");
2331
}
2432

2533
SynthesisPieceModel::SynthesisPieceModel(Synth::ProjectSynthesisContext *context, QObject *parent)
@@ -28,6 +36,7 @@ namespace SynthVisualizer::Internal {
2836
}
2937

3038
SynthesisPieceModel::~SynthesisPieceModel() {
39+
clearRangeIndicators();
3140
disconnectPieceSignals();
3241
disconnectClipSignals();
3342
disconnect(m_windowHandleConnection);
@@ -83,6 +92,10 @@ namespace SynthVisualizer::Internal {
8392
Q_EMIT singingClipChanged();
8493
}
8594

95+
sflow::RangeSequenceViewModel *SynthesisPieceModel::rangeIndicatorSequenceViewModel() const {
96+
return m_rangeIndicatorSequenceViewModel;
97+
}
98+
8699
int SynthesisPieceModel::rowCount(const QModelIndex &parent) const {
87100
return parent.isValid() ? 0 : m_pieces.size();
88101
}
@@ -159,6 +172,26 @@ namespace SynthVisualizer::Internal {
159172
);
160173
}
161174

175+
QObject *SynthesisPieceModel::pieceForRangeIndicator(
176+
sflow::RangeIndicatorViewModel *viewItem) const {
177+
return m_pieceMap.value(viewItem);
178+
}
179+
180+
bool SynthesisPieceModel::isPieceTaskActive(QObject *pieceObject) const {
181+
auto piece = qobject_cast<Synth::SynthesisPiece *>(pieceObject);
182+
return piece && (piece->state() == Synth::SynthesisPiece::Queued ||
183+
piece->state() == Synth::SynthesisPiece::Synthesizing);
184+
}
185+
186+
QString SynthesisPieceModel::verifiedDiagnosticFilePath(QObject *pieceObject) const {
187+
auto piece = qobject_cast<Synth::SynthesisPiece *>(pieceObject);
188+
if (!piece) {
189+
return {};
190+
}
191+
const auto path = piece->diagnosticFilePath();
192+
return path.isEmpty() || !QFileInfo::exists(path) ? QString() : path;
193+
}
194+
162195
void SynthesisPieceModel::setSynthesisContext(Synth::ProjectSynthesisContext *context) {
163196
if (m_context == context) {
164197
return;
@@ -209,6 +242,8 @@ namespace SynthVisualizer::Internal {
209242
}
210243
endResetModel();
211244

245+
reconcileRangeIndicators();
246+
212247
for (auto piecePointer : std::as_const(m_pieces)) {
213248
auto piece = piecePointer.data();
214249
if (!piece) {
@@ -227,6 +262,7 @@ namespace SynthVisualizer::Internal {
227262
if (!piece) {
228263
return;
229264
}
265+
updateRangeIndicator(piece);
230266
for (int row = 0; row < m_pieces.size(); ++row) {
231267
if (m_pieces.at(row) != piece) {
232268
continue;
@@ -249,6 +285,9 @@ namespace SynthVisualizer::Internal {
249285
}
250286

251287
void SynthesisPieceModel::updateClipPosition() {
288+
for (auto piece : m_rangeIndicatorViewItemMap.keys()) {
289+
updateRangeIndicator(piece);
290+
}
252291
if (m_pieces.isEmpty()) {
253292
return;
254293
}
@@ -257,6 +296,72 @@ namespace SynthVisualizer::Internal {
257296
});
258297
}
259298

299+
void SynthesisPieceModel::reconcileRangeIndicators() {
300+
QSet<Synth::SynthesisPiece *> livePieces;
301+
for (const auto piecePointer : std::as_const(m_pieces)) {
302+
if (auto piece = piecePointer.data()) {
303+
livePieces.insert(piece);
304+
}
305+
}
306+
307+
for (auto piece : m_rangeIndicatorViewItemMap.keys()) {
308+
if (livePieces.contains(piece)) {
309+
continue;
310+
}
311+
auto viewItem = m_rangeIndicatorViewItemMap.take(piece);
312+
m_pieceMap.remove(viewItem);
313+
m_rangeIndicatorSequenceViewModel->removeItem(viewItem);
314+
viewItem->deleteLater();
315+
}
316+
317+
for (auto piece : std::as_const(livePieces)) {
318+
auto viewItem = m_rangeIndicatorViewItemMap.value(piece);
319+
if (!viewItem) {
320+
viewItem = new sflow::RangeIndicatorViewModel(this);
321+
m_rangeIndicatorViewItemMap.insert(piece, viewItem);
322+
m_pieceMap.insert(viewItem, piece);
323+
updateRangeIndicator(piece);
324+
m_rangeIndicatorSequenceViewModel->insertItem(viewItem);
325+
} else {
326+
updateRangeIndicator(piece);
327+
}
328+
}
329+
}
330+
331+
void SynthesisPieceModel::updateRangeIndicator(Synth::SynthesisPiece *piece) {
332+
auto viewItem = m_rangeIndicatorViewItemMap.value(piece);
333+
if (!viewItem || !m_singingClip) {
334+
return;
335+
}
336+
viewItem->setPosition(qRound(m_singingClip->start() + piece->position()));
337+
viewItem->setLength(qRound(piece->length()));
338+
viewItem->setContent(statusText(piece));
339+
switch (piece->state()) {
340+
case Synth::SynthesisPiece::Ready:
341+
viewItem->setType(SVS::SVSCraft::CT_Accent);
342+
break;
343+
case Synth::SynthesisPiece::Failed:
344+
viewItem->setType(SVS::SVSCraft::CT_Error);
345+
break;
346+
case Synth::SynthesisPiece::Idle:
347+
case Synth::SynthesisPiece::Stale:
348+
case Synth::SynthesisPiece::Queued:
349+
case Synth::SynthesisPiece::Synthesizing:
350+
viewItem->setType(SVS::SVSCraft::CT_Normal);
351+
break;
352+
}
353+
}
354+
355+
void SynthesisPieceModel::clearRangeIndicators() {
356+
const auto viewItems = m_pieceMap.keys();
357+
for (auto viewItem : viewItems) {
358+
m_rangeIndicatorSequenceViewModel->removeItem(viewItem);
359+
delete viewItem;
360+
}
361+
m_rangeIndicatorViewItemMap.clear();
362+
m_pieceMap.clear();
363+
}
364+
260365
QString SynthesisPieceModel::statusText(const Synth::SynthesisPiece *piece) const {
261366
switch (piece->state()) {
262367
case Synth::SynthesisPiece::Idle:

src/plugins/synthvisualizer/internal/model/SynthesisPieceModel.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include <QMetaObject>
1111
#include <QPair>
1212
#include <QPointer>
13+
#include <QString>
1314
#include <qqmlintegration.h>
1415

1516
namespace Core {
@@ -26,13 +27,19 @@ namespace Synth {
2627
enum class SynthesisTaskType;
2728
}
2829

30+
namespace sflow {
31+
class RangeIndicatorViewModel;
32+
class RangeSequenceViewModel;
33+
}
34+
2935
namespace SynthVisualizer::Internal {
3036

3137
class SynthesisPieceModel : public QAbstractListModel {
3238
Q_OBJECT
3339
QML_ELEMENT
3440
Q_PROPERTY(Core::ProjectWindowInterface *windowHandle READ windowHandle WRITE setWindowHandle NOTIFY windowHandleChanged)
3541
Q_PROPERTY(dspx::SingingClip *singingClip READ singingClip WRITE setSingingClip NOTIFY singingClipChanged)
42+
Q_PROPERTY(sflow::RangeSequenceViewModel *rangeIndicatorSequenceViewModel READ rangeIndicatorSequenceViewModel CONSTANT)
3643

3744
public:
3845
enum Role {
@@ -58,12 +65,17 @@ namespace SynthVisualizer::Internal {
5865
dspx::SingingClip *singingClip() const;
5966
void setSingingClip(dspx::SingingClip *clip);
6067

68+
sflow::RangeSequenceViewModel *rangeIndicatorSequenceViewModel() const;
69+
6170
int rowCount(const QModelIndex &parent = {}) const override;
6271
QVariant data(const QModelIndex &index, int role) const override;
6372
QHash<int, QByteArray> roleNames() const override;
6473

6574
Q_INVOKABLE bool cancelPieceTask(QObject *piece);
6675
Q_INVOKABLE void resynthesizePiece(QObject *piece, int fromType, bool readCache, bool writeCache);
76+
Q_INVOKABLE QObject *pieceForRangeIndicator(sflow::RangeIndicatorViewModel *viewItem) const;
77+
Q_INVOKABLE bool isPieceTaskActive(QObject *piece) const;
78+
Q_INVOKABLE QString verifiedDiagnosticFilePath(QObject *piece) const;
6779

6880
Q_SIGNALS:
6981
void windowHandleChanged();
@@ -74,6 +86,9 @@ namespace SynthVisualizer::Internal {
7486
void rebuild();
7587
void updatePiece(Synth::SynthesisPiece *piece);
7688
void updateClipPosition();
89+
void reconcileRangeIndicators();
90+
void updateRangeIndicator(Synth::SynthesisPiece *piece);
91+
void clearRangeIndicators();
7792
QString statusText(const Synth::SynthesisPiece *piece) const;
7893
QString taskTypeText(Synth::SynthesisTaskType type) const;
7994
QPair<double, double> absoluteRange(const Synth::SynthesisPiece *piece) const;
@@ -88,6 +103,9 @@ namespace SynthVisualizer::Internal {
88103
QList<QMetaObject::Connection> m_contextConnections;
89104
QList<QMetaObject::Connection> m_pieceConnections;
90105
QList<QMetaObject::Connection> m_clipConnections;
106+
sflow::RangeSequenceViewModel *m_rangeIndicatorSequenceViewModel{};
107+
QHash<Synth::SynthesisPiece *, sflow::RangeIndicatorViewModel *> m_rangeIndicatorViewItemMap;
108+
QHash<sflow::RangeIndicatorViewModel *, Synth::SynthesisPiece *> m_pieceMap;
91109
};
92110

93111
}

0 commit comments

Comments
 (0)