Skip to content

Commit a11ac4e

Browse files
committed
Add insertNote action
1 parent 0bee621 commit a11ac4e

File tree

5 files changed

+165
-3
lines changed

5 files changed

+165
-3
lines changed

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

Lines changed: 63 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@
3535
#include <dspxmodel/Track.h>
3636
#include <dspxmodel/TrackList.h>
3737
#include <dspxmodel/BusControl.h>
38+
#include <dspxmodel/NoteSelectionModel.h>
39+
#include <dspxmodel/Note.h>
40+
#include <dspxmodel/NoteSequence.h>
3841

3942
#include <coreplugin/DspxDocument.h>
4043
#include <coreplugin/ProjectTimeline.h>
@@ -222,7 +225,7 @@ namespace Core {
222225
return;
223226

224227
auto selectionModel = document()->selectionModel();
225-
auto trackSelectionModel = selectionModel ? selectionModel->trackSelectionModel() : nullptr;
228+
auto trackSelectionModel = selectionModel->trackSelectionModel();
226229
auto currentTrack = trackSelectionModel ? trackSelectionModel->currentItem() : nullptr;
227230
if (!currentTrack) {
228231
if (auto currentClip = qobject_cast<dspx::Clip *>(selectionModel ? selectionModel->currentItem() : nullptr)) {
@@ -292,9 +295,66 @@ namespace Core {
292295
});
293296

294297
if (success && newClip) {
295-
if (selectionModel) {
296-
selectionModel->select(newClip, dspx::SelectionModel::Select | dspx::SelectionModel::SetCurrentItem | dspx::SelectionModel::ClearPreviousSelection);
298+
selectionModel->select(newClip, dspx::SelectionModel::Select | dspx::SelectionModel::SetCurrentItem | dspx::SelectionModel::ClearPreviousSelection);
299+
}
300+
}
301+
302+
void InsertItemScenario::insertNote() const {
303+
Q_D(const InsertItemScenario);
304+
if (!document() || !d->projectTimeline || !window())
305+
return;
306+
307+
auto model = document()->model();
308+
auto selectionModel = document()->selectionModel();
309+
auto noteSelectionModel = selectionModel->noteSelectionModel();
310+
311+
auto noteSequence = noteSelectionModel->noteSequenceWithSelectedItems();
312+
if (!noteSequence)
313+
return;
314+
315+
auto clip = noteSequence->singingClip();
316+
317+
// Calculate initial position: playback position - clip position
318+
const int clipPosition = clip->position();
319+
const int initialPosition = qMax(0, d->projectTimeline->position() - clipPosition);
320+
321+
QQmlComponent component(RuntimeInterface::qmlEngine(), "DiffScope.Core", "InsertNoteDialog");
322+
QVariantMap properties;
323+
properties.insert("timeline", QVariant::fromValue(d->projectTimeline->musicTimeline()));
324+
properties.insert("notePosition", initialPosition);
325+
properties.insert("noteLength", 480);
326+
properties.insert("notePitch", 60); // Default to middle C (C4)
327+
properties.insert("noteLyric", QString()); // TODO: determine initial lyric
328+
auto dialog = createAndPositionDialog(&component, properties);
329+
if (!DocumentEditScenarioPrivate::execDialog(dialog))
330+
return;
331+
332+
const auto notePosition = qMax(0, dialog->property("notePosition").toInt());
333+
const auto noteLength = qMax(1, dialog->property("noteLength").toInt());
334+
const auto notePitch = qBound(0, dialog->property("notePitch").toInt(), 127);
335+
const auto noteLyric = dialog->property("noteLyric").toString();
336+
337+
dspx::Note *newNote = nullptr;
338+
bool success = false;
339+
document()->transactionController()->beginScopedTransaction(tr("Inserting note"), [=, &newNote, &success] {
340+
newNote = model->createNote();
341+
newNote->setPos(notePosition);
342+
newNote->setLength(noteLength);
343+
newNote->setKeyNum(notePitch);
344+
newNote->setLyric(noteLyric);
345+
if (!noteSequence->insertItem(newNote)) {
346+
model->destroyItem(newNote);
347+
newNote = nullptr;
348+
return false;
297349
}
350+
success = true;
351+
return true;
352+
}, [] {
353+
qCCritical(lcInsertItemScenario) << "Failed to insert note in exclusive transaction";
354+
});
355+
356+
if (success && newNote) {
357+
selectionModel->select(newNote, dspx::SelectionModel::Select | dspx::SelectionModel::SetCurrentItem | dspx::SelectionModel::ClearPreviousSelection);
298358
}
299359
}
300360

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ namespace Core {
3232
Q_INVOKABLE void insertTrack() const;
3333
Q_INVOKABLE void insertLabel() const;
3434
Q_INVOKABLE void insertSingingClip() const;
35+
Q_INVOKABLE void insertNote() const;
3536

3637
Q_SIGNALS:
3738
void projectTimelineChanged();

src/plugins/coreplugin/qml/actions/InsertItemAddOnActions.qml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,12 @@ ActionCollection {
4545
onTriggered: Qt.callLater(() => insertItemScenario.insertSingingClip())
4646
}
4747
}
48+
49+
ActionItem {
50+
actionId: "org.diffscope.core.insert.insertNote"
51+
Action {
52+
enabled: Boolean(d.windowHandle?.projectDocumentContext.document.selectionModel.noteSelectionModel.noteSequenceWithSelectedItems)
53+
onTriggered: Qt.callLater(() => insertItemScenario.insertNote())
54+
}
55+
}
4856
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
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 MusicTimeline timeline
16+
property int notePosition
17+
property int noteLength
18+
property int notePitch
19+
property string noteLyric
20+
21+
title: qsTr("Insert Note")
22+
23+
onAboutToShow: notePositionSpinBox.forceActiveFocus()
24+
25+
GridLayout {
26+
anchors.fill: parent
27+
columns: 2
28+
29+
Label {
30+
id: notePositionLabel
31+
text: qsTr("Onset Position")
32+
}
33+
MusicTimeOffsetSpinBox {
34+
id: notePositionSpinBox
35+
Accessible.labelledBy: notePositionLabel
36+
Accessible.name: notePositionLabel.text
37+
Layout.fillWidth: true
38+
value: dialog.notePosition
39+
from: 0
40+
to: 2147483647
41+
onValueModified: dialog.notePosition = value
42+
}
43+
44+
Label {
45+
id: noteLengthLabel
46+
text: qsTr("Length")
47+
}
48+
MusicTimeOffsetSpinBox {
49+
id: noteLengthSpinBox
50+
Accessible.labelledBy: noteLengthLabel
51+
Accessible.name: noteLengthLabel.text
52+
Layout.fillWidth: true
53+
value: Math.max(1, dialog.noteLength)
54+
from: 1
55+
to: 2147483647
56+
onValueModified: dialog.noteLength = value
57+
}
58+
59+
Label {
60+
id: notePitchLabel
61+
text: qsTr("Pitch")
62+
}
63+
MusicPitchSpinBox {
64+
id: notePitchSpinBox
65+
Accessible.labelledBy: notePitchLabel
66+
Accessible.name: notePitchLabel.text
67+
Layout.fillWidth: true
68+
value: dialog.notePitch
69+
from: 0
70+
to: 127
71+
onValueModified: dialog.notePitch = value
72+
}
73+
74+
Label {
75+
id: noteLyricLabel
76+
text: qsTr("Lyric")
77+
}
78+
TextField {
79+
id: noteLyricTextField
80+
Accessible.labelledBy: noteLyricLabel
81+
Accessible.name: noteLyricLabel.text
82+
Layout.fillWidth: true
83+
text: dialog.noteLyric
84+
onTextEdited: dialog.noteLyric = text
85+
}
86+
}
87+
88+
standardButtons: DialogButtonBox.Ok
89+
}

src/plugins/coreplugin/res/org.diffscope.core_actions.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,9 @@
105105
<action id="org.diffscope.core.insert.addTrack" icon="list_bar_add" />
106106
<action id="org.diffscope.core.insert.insertTrack^" icon="list_bar_add" />
107107
<action id="org.diffscope.core.insert.insertLabel^" icon="tag_add" />
108+
<!--TODO: make "add" icons for insert actions-->
108109
<action id="org.diffscope.core.insert.insertSingingClip^" icon="mic" />
110+
<action id="org.diffscope.core.insert.insertNote^" icon="music_note_1" />
109111

110112
<action id="org.diffscope.core.window.&amp;nextProjectWindow" description="Switch to the next project window" shortcut="Alt+J" />
111113
<action id="org.diffscope.core.window.&amp;previousProjectWindow" description="Switch to the previous project window" shortcut="Alt+K" />
@@ -245,6 +247,7 @@
245247
<action id="org.diffscope.core.insert.insertTrack" />
246248
<action id="org.diffscope.core.insert.insertLabel" />
247249
<action id="org.diffscope.core.insert.insertSingingClip" />
250+
<action id="org.diffscope.core.insert.insertNote" />
248251
</menu>
249252
<menu id="org.diffscope.core.&amp;view">
250253
<group id="org.diffscope.core.workspaceActions">
@@ -420,6 +423,7 @@
420423
</menu>
421424

422425
<menu id="org.diffscope.core.noteSceneContextMenu">
426+
<action id="org.diffscope.core.insert.insertNote" />
423427
<group id="org.diffscope.core.genericSceneContextMenuActions" />
424428
</menu>
425429
</layouts>

0 commit comments

Comments
 (0)