Skip to content

Commit 29d2381

Browse files
committed
Update phoneme editor
1 parent fedc1cf commit 29d2381

6 files changed

Lines changed: 354 additions & 9 deletions

File tree

src/plugins/coreplugin/internal/PhonemeListModel.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ namespace Core::Internal {
7474
return phoneme->start();
7575
case OnsetRole:
7676
return phoneme->onset();
77+
case PhonemeRole:
78+
return QVariant::fromValue(phoneme);
7779
default:
7880
return {};
7981
}
@@ -117,7 +119,8 @@ namespace Core::Internal {
117119
{TokenRole, "token"},
118120
{LanguageRole, "language"},
119121
{StartRole, "start"},
120-
{OnsetRole, "onset"}
122+
{OnsetRole, "onset"},
123+
{PhonemeRole, "phoneme"}
121124
};
122125
return roles;
123126
}

src/plugins/coreplugin/internal/PhonemeListModel.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
#define DIFFSCOPE_COREPLUGIN_PHONEMELISTMODEL_H
33

44
#include <QAbstractItemModel>
5+
#include <qqmlintegration.h>
56

67
namespace dspx {
78
class Phoneme;
@@ -12,6 +13,7 @@ namespace Core::Internal {
1213

1314
class PhonemeListModel : public QAbstractItemModel {
1415
Q_OBJECT
16+
QML_ELEMENT
1517

1618
Q_PROPERTY(dspx::PhonemeSequence *phonemeSequence READ phonemeSequence WRITE setPhonemeSequence NOTIFY phonemeSequenceChanged)
1719

@@ -21,6 +23,7 @@ namespace Core::Internal {
2123
LanguageRole,
2224
StartRole,
2325
OnsetRole,
26+
PhonemeRole,
2427
};
2528
Q_ENUM(Roles)
2629

src/plugins/coreplugin/project/scenarios/InsertItemScenario.cpp

Lines changed: 78 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,9 @@
3838
#include <dspxmodel/NoteSelectionModel.h>
3939
#include <dspxmodel/Note.h>
4040
#include <dspxmodel/NoteSequence.h>
41+
#include <dspxmodel/PhonemeInfo.h>
42+
#include <dspxmodel/PhonemeSequence.h>
43+
#include <dspxmodel/Phoneme.h>
4144

4245
#include <coreplugin/DspxDocument.h>
4346
#include <coreplugin/ProjectTimeline.h>
@@ -313,23 +316,29 @@ namespace Core {
313316
}
314317
}
315318

316-
void InsertItemScenario::insertNote() const {
319+
void InsertItemScenario::insertNote(dspx::SingingClip *clip) const {
317320
Q_D(const InsertItemScenario);
318321
if (!document() || !d->projectTimeline || !window())
319322
return;
320323

321324
auto model = document()->model();
322325
auto selectionModel = document()->selectionModel();
323-
auto noteSelectionModel = selectionModel->noteSelectionModel();
324326

325-
auto noteSequence = noteSelectionModel->noteSequenceWithSelectedItems();
326-
if (!noteSequence)
327-
return;
327+
dspx::NoteSequence *noteSequence = nullptr;
328+
329+
// If clip is provided, use it and its notes
330+
if (clip) {
331+
noteSequence = clip->notes();
332+
} else {
333+
auto noteSelectionModel = selectionModel->noteSelectionModel();
334+
noteSequence = noteSelectionModel->noteSequenceWithSelectedItems();
335+
if (!noteSequence)
336+
return;
337+
clip = noteSequence->singingClip();
338+
}
328339

329340
qCInfo(lcInsertItemScenario) << "Inserting note";
330341

331-
auto clip = noteSequence->singingClip();
332-
333342
// Calculate initial position: playback position - clip position
334343
const int clipPosition = clip->position();
335344
const int initialPosition = qMax(0, d->projectTimeline->position() - clipPosition);
@@ -376,6 +385,68 @@ namespace Core {
376385
}
377386
}
378387

388+
void InsertItemScenario::insertPhoneme(dspx::Note *note) const {
389+
Q_D(const InsertItemScenario);
390+
if (!document() || !window())
391+
return;
392+
393+
auto model = document()->model();
394+
auto selectionModel = document()->selectionModel();
395+
396+
// If note is not provided, try to get it from the selection
397+
if (!note) {
398+
if (selectionModel->selectionType() == dspx::SelectionModel::ST_Note) {
399+
auto noteSelectionModel = selectionModel->noteSelectionModel();
400+
const auto selectedNotes = noteSelectionModel->selectedItems();
401+
if (selectedNotes.isEmpty())
402+
return;
403+
note = selectedNotes.first();
404+
} else {
405+
return;
406+
}
407+
}
408+
409+
qCInfo(lcInsertItemScenario) << "Inserting phoneme";
410+
411+
auto phonemeSequence = note->phonemes()->edited();
412+
413+
QQmlComponent component(RuntimeInterface::qmlEngine(), "DiffScope.Core", "InsertPhonemeDialog");
414+
QVariantMap properties;
415+
properties.insert("token", QString());
416+
properties.insert("start", 0);
417+
properties.insert("language", QString());
418+
properties.insert("onset", false);
419+
auto dialog = createAndPositionDialog(&component, properties);
420+
if (!DocumentEditScenarioPrivate::execDialog(dialog))
421+
return;
422+
423+
const auto token = dialog->property("token").toString();
424+
const auto start = dialog->property("start").toInt();
425+
const auto language = dialog->property("language").toString();
426+
const auto onset = dialog->property("onset").toBool();
427+
qCDebug(lcInsertItemScenario) << "Inserting phoneme with token" << token << "start" << start << "language" << language << "onset" << onset << "to note" << note;
428+
429+
dspx::Phoneme *newPhoneme = nullptr;
430+
bool success = false;
431+
document()->transactionController()->beginScopedTransaction(tr("Inserting phoneme"), [=, &newPhoneme, &success] {
432+
newPhoneme = model->createPhoneme();
433+
newPhoneme->setToken(token);
434+
newPhoneme->setStart(start);
435+
newPhoneme->setLanguage(language);
436+
newPhoneme->setOnset(onset);
437+
if (!phonemeSequence->insertItem(newPhoneme)) {
438+
model->destroyItem(newPhoneme);
439+
newPhoneme = nullptr;
440+
return false;
441+
}
442+
success = true;
443+
qCDebug(lcInsertItemScenario) << "Inserted phoneme" << newPhoneme;
444+
return true;
445+
}, [] {
446+
qCCritical(lcInsertItemScenario) << "Failed to insert phoneme in exclusive transaction";
447+
});
448+
}
449+
379450
}
380451

381452
#include "moc_InsertItemScenario.cpp"

src/plugins/coreplugin/project/scenarios/InsertItemScenario.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
namespace dspx {
77
class Track;
88
class Label;
9+
class SingingClip;
10+
class Note;
911
}
1012

1113
namespace Core {
@@ -32,7 +34,8 @@ namespace Core {
3234
Q_INVOKABLE void insertTrack() const;
3335
Q_INVOKABLE void insertLabel() const;
3436
Q_INVOKABLE void insertSingingClip() const;
35-
Q_INVOKABLE void insertNote() const;
37+
Q_INVOKABLE void insertNote(dspx::SingingClip *clip = nullptr) const;
38+
Q_INVOKABLE void insertPhoneme(dspx::Note *note = nullptr) const;
3639

3740
Q_SIGNALS:
3841
void projectTimelineChanged();
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import QtQml
2+
import QtQuick
3+
import QtQuick.Controls
4+
import QtQuick.Layouts
5+
6+
import SVSCraft
7+
import SVSCraft.UIComponents
8+
9+
import DiffScope.UIShell
10+
import DiffScope.Core
11+
12+
Dialog {
13+
id: dialog
14+
15+
property string token
16+
property int start
17+
property string language
18+
property bool onset
19+
20+
title: qsTr("Insert Phoneme")
21+
22+
onAboutToShow: tokenTextField.forceActiveFocus()
23+
24+
GridLayout {
25+
anchors.fill: parent
26+
columns: 2
27+
28+
Label {
29+
id: tokenLabel
30+
text: qsTr("Token")
31+
}
32+
TextField {
33+
id: tokenTextField
34+
Accessible.labelledBy: tokenLabel
35+
Accessible.name: tokenLabel.text
36+
Layout.fillWidth: true
37+
text: dialog.token
38+
onTextEdited: dialog.token = text
39+
}
40+
41+
Label {
42+
id: startLabel
43+
text: qsTr("Start (ms)")
44+
}
45+
SpinBox {
46+
id: startSpinBox
47+
Accessible.labelledBy: startLabel
48+
Accessible.name: startLabel.text
49+
Layout.fillWidth: true
50+
value: dialog.start
51+
from: -2147483648
52+
to: 2147483647
53+
onValueModified: dialog.start = value
54+
}
55+
56+
Label {
57+
id: languageLabel
58+
text: qsTr("Language")
59+
}
60+
TextField {
61+
id: languageTextField
62+
Accessible.labelledBy: languageLabel
63+
Accessible.name: languageLabel.text
64+
Layout.fillWidth: true
65+
text: dialog.language
66+
onTextEdited: dialog.language = text
67+
}
68+
69+
CheckBox {
70+
id: onsetCheckBox
71+
Layout.columnSpan: 2
72+
Layout.fillWidth: true
73+
text: qsTr("Onset")
74+
checked: dialog.onset
75+
onClicked: dialog.onset = checked
76+
}
77+
}
78+
79+
standardButtons: DialogButtonBox.Ok
80+
}

0 commit comments

Comments
 (0)