Skip to content

Commit c89d560

Browse files
Add "Play from selection" shortcut
1 parent ff3d64a commit c89d560

13 files changed

+117
-20
lines changed

src/app/configs/data/shortcuts.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,11 @@
801801
<seq>Space</seq>
802802
<autorepeat>0</autorepeat>
803803
</SC>
804+
<SC>
805+
<key>play-from-selection</key>
806+
<seq>Shift+Space</seq>
807+
<autorepeat>0</autorepeat>
808+
</SC>
804809
<SC>
805810
<key>pause-and-select</key>
806811
<seq>Ctrl+Space</seq>

src/app/configs/data/shortcuts_azerty.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -842,6 +842,11 @@
842842
<seq>Space</seq>
843843
<autorepeat>0</autorepeat>
844844
</SC>
845+
<SC>
846+
<key>play-from-selection</key>
847+
<seq>Shift+Space</seq>
848+
<autorepeat>0</autorepeat>
849+
</SC>
845850
<SC>
846851
<key>pause-and-select</key>
847852
<seq>Ctrl+Space</seq>

src/app/configs/data/shortcuts_mac.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -801,6 +801,11 @@
801801
<seq>Space</seq>
802802
<autorepeat>0</autorepeat>
803803
</SC>
804+
<SC>
805+
<key>play-from-selection</key>
806+
<seq>Shift+Space</seq>
807+
<autorepeat>0</autorepeat>
808+
</SC>
804809
<SC>
805810
<key>pause-and-select</key>
806811
<seq>Alt+Space</seq>

src/notation/inotationinteraction.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,8 @@ class INotationInteraction
171171
virtual void startEditGrip(EngravingItem* element, mu::engraving::Grip grip) = 0;
172172
virtual void endEditGrip() = 0;
173173

174-
virtual bool isElementEditStarted() const = 0;
174+
virtual bool isEditingElement() const = 0;
175+
virtual muse::async::Notification isEditingElementChanged() const = 0;
175176
virtual void startEditElement(EngravingItem* element) = 0;
176177
virtual void changeEditElement(EngravingItem* newElement) = 0;
177178
virtual bool isEditAllowed(QKeyEvent* event) = 0;

src/notation/internal/notationactioncontroller.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -712,7 +712,7 @@ void NotationActionController::resetState()
712712
if (interaction->isTextEditingStarted()) {
713713
interaction->endEditElement();
714714
return;
715-
} else if (interaction->isElementEditStarted()) {
715+
} else if (interaction->isEditingElement()) {
716716
interaction->endEditElement();
717717
}
718718

@@ -2349,7 +2349,7 @@ bool NotationActionController::isEditingElement() const
23492349
{
23502350
auto interaction = currentNotationInteraction();
23512351
if (interaction) {
2352-
return interaction->isElementEditStarted() || interaction->isDragStarted();
2352+
return interaction->isEditingElement() || interaction->isDragStarted();
23532353
}
23542354
return false;
23552355
}

src/notation/internal/notationinteraction.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1130,10 +1130,8 @@ void NotationInteraction::clearSelection()
11301130
{
11311131
TRACEFUNC;
11321132

1133-
if (isElementEditStarted()) {
1133+
if (isEditingElement()) {
11341134
endEditElement();
1135-
} else if (m_editData.element) {
1136-
m_editData.element = nullptr;
11371135
}
11381136

11391137
if (isDragStarted()) {
@@ -1295,7 +1293,7 @@ void NotationInteraction::drag(const PointF& fromPos, const PointF& toPos, DragM
12951293
m_dragData.ed.pos = toPos;
12961294
m_dragData.ed.modifiers = keyboardModifier(QGuiApplication::keyboardModifiers());
12971295

1298-
m_dragData.ed.isEditMode = isElementEditStarted();
1296+
m_dragData.ed.isEditMode = isEditingElement();
12991297

13001298
if (isTextEditingStarted()) {
13011299
m_editData.pos = toPos;
@@ -3767,7 +3765,7 @@ void NotationInteraction::addToSelection(MoveDirection d, MoveSelectionType type
37673765
bool NotationInteraction::moveSelectionAvailable(MoveSelectionType type) const
37683766
{
37693767
if (type != MoveSelectionType::EngravingItem) {
3770-
return !isElementEditStarted();
3768+
return !isEditingElement();
37713769
}
37723770

37733771
EngravingItem* el = score()->selection().element();
@@ -3785,7 +3783,7 @@ bool NotationInteraction::moveSelectionAvailable(MoveSelectionType type) const
37853783
return true;
37863784
}
37873785

3788-
return m_editData.element && m_editData.element->isTextBase() ? !isTextEditingStarted() : !isElementEditStarted();
3786+
return m_editData.element && m_editData.element->isTextBase() ? !isTextEditingStarted() : !isEditingElement();
37893787
}
37903788

37913789
void NotationInteraction::moveSelection(MoveDirection d, MoveSelectionType type)
@@ -4099,7 +4097,7 @@ void NotationInteraction::moveElementSelection(MoveDirection d)
40994097
return;
41004098
}
41014099

4102-
if (isElementEditStarted()) {
4100+
if (isEditingElement()) {
41034101
endEditElement();
41044102
}
41054103

@@ -4308,6 +4306,7 @@ void NotationInteraction::startEditText(EngravingItem* element, const PointF& cu
43084306

43094307
m_editData.element->startEdit(m_editData);
43104308

4309+
m_isEditingElementChanged.notify();
43114310
notifyAboutTextEditingStarted();
43124311
notifyAboutTextEditingChanged();
43134312
}
@@ -4448,6 +4447,8 @@ void NotationInteraction::endEditText()
44484447

44494448
TextBase* editedElement = toTextBase(m_editData.element);
44504449
doEndEditElement();
4450+
4451+
m_isEditingElementChanged.notify();
44514452
notifyAboutTextEditingEnded(editedElement);
44524453

44534454
notifyAboutTextEditingChanged();
@@ -4622,7 +4623,7 @@ void NotationInteraction::updateDragAnchorLines()
46224623
setAnchorLines(anchorLines);
46234624
}
46244625

4625-
bool NotationInteraction::isElementEditStarted() const
4626+
bool NotationInteraction::isEditingElement() const
46264627
{
46274628
return m_editData.element != nullptr;
46284629
}
@@ -4633,7 +4634,7 @@ void NotationInteraction::startEditElement(EngravingItem* element)
46334634
return;
46344635
}
46354636

4636-
if (isElementEditStarted()) {
4637+
if (isEditingElement()) {
46374638
return;
46384639
}
46394640

@@ -4645,6 +4646,8 @@ void NotationInteraction::startEditElement(EngravingItem* element)
46454646
element->startEdit(m_editData);
46464647
m_editData.element = element;
46474648
}
4649+
4650+
m_isEditingElementChanged.notify();
46484651
}
46494652

46504653
void NotationInteraction::changeEditElement(EngravingItem* newElement)
@@ -4794,9 +4797,15 @@ void NotationInteraction::endEditElement()
47944797
doEndEditElement();
47954798
resetAnchorLines();
47964799

4800+
m_isEditingElementChanged.notify();
47974801
notifyAboutNotationChanged();
47984802
}
47994803

4804+
muse::async::Notification NotationInteraction::isEditingElementChanged() const
4805+
{
4806+
return m_isEditingElementChanged;
4807+
}
4808+
48004809
void NotationInteraction::updateTimeTickAnchors(QKeyEvent* event)
48014810
{
48024811
EngravingItem* selectedElement = m_selection->element();
@@ -6414,7 +6423,7 @@ bool NotationInteraction::needEndTextEditing(const std::vector<EngravingItem*>&
64146423

64156424
bool NotationInteraction::needEndElementEditing(const std::vector<EngravingItem*>& newSelectedElements) const
64166425
{
6417-
if (!isElementEditStarted()) {
6426+
if (!isEditingElement()) {
64186427
return false;
64196428
}
64206429

src/notation/internal/notationinteraction.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,8 @@ class NotationInteraction : public INotationInteraction, public muse::Injectable
180180
void startEditGrip(EngravingItem* element, mu::engraving::Grip grip) override;
181181
void endEditGrip() override;
182182

183-
bool isElementEditStarted() const override;
183+
bool isEditingElement() const override;
184+
muse::async::Notification isEditingElementChanged() const override;
184185
void startEditElement(EngravingItem* element) override;
185186
void changeEditElement(EngravingItem* newElement) override;
186187
bool isEditAllowed(QKeyEvent* event) override;
@@ -534,6 +535,8 @@ class NotationInteraction : public INotationInteraction, public muse::Injectable
534535

535536
mu::engraving::EditData m_editData;
536537

538+
muse::async::Notification m_isEditingElementChanged;
539+
537540
muse::async::Notification m_textEditingStarted;
538541
muse::async::Notification m_textEditingChanged;
539542
muse::async::Channel<TextBase*> m_textEditingEnded;

src/notation/tests/mocks/notationinteractionmock.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ class NotationInteractionMock : public INotationInteraction
132132
MOCK_METHOD(void, startEditGrip, (EngravingItem*, mu::engraving::Grip), (override));
133133
MOCK_METHOD(void, endEditGrip, (), (override));
134134

135-
MOCK_METHOD(bool, isElementEditStarted, (), (const, override));
135+
MOCK_METHOD(bool, isEditingElement, (), (const, override));
136+
MOCK_METHOD(muse::async::Notification, isEditingElementChanged, (), (const, override));
136137
MOCK_METHOD(void, startEditElement, (EngravingItem*), (override));
137138
MOCK_METHOD(void, changeEditElement, (EngravingItem*), (override));
138139
MOCK_METHOD(bool, isEditAllowed, (QKeyEvent*), (override));

src/notation/view/notationviewinputcontroller.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,7 @@ void NotationViewInputController::mouseMoveEvent(QMouseEvent* event)
10841084
const EngravingItem* hitElement = hitElementContext().element;
10851085

10861086
// drag element
1087-
if ((hitElement && (hitElement->isMovable() || viewInteraction()->isElementEditStarted()))
1087+
if ((hitElement && (hitElement->isMovable() || viewInteraction()->isEditingElement()))
10881088
|| viewInteraction()->isGripEditStarted()) {
10891089
if (hitElement && !viewInteraction()->isDragStarted()) {
10901090
startDragElements(hitElement->type(), hitElement->offset());
@@ -1364,7 +1364,7 @@ bool NotationViewInputController::shortcutOverrideEvent(QKeyEvent* event)
13641364
return true;
13651365
}
13661366

1367-
if (viewInteraction()->isElementEditStarted()) {
1367+
if (viewInteraction()->isEditingElement()) {
13681368
return viewInteraction()->isEditAllowed(event);
13691369
}
13701370

@@ -1388,7 +1388,7 @@ void NotationViewInputController::keyPressEvent(QKeyEvent* event)
13881388
m_mouseDownInfo.dragAction = MouseDownInfo::Nothing;
13891389
m_view->asItem()->setCursor({});
13901390
event->accept();
1391-
} else if (viewInteraction()->isElementEditStarted()) {
1391+
} else if (viewInteraction()->isEditingElement()) {
13921392
viewInteraction()->editElement(event);
13931393
if (key == Qt::Key_Shift) {
13941394
viewInteraction()->updateTimeTickAnchors(event);

src/playback/internal/playbackcontroller.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ using namespace mu::notation;
4444
using namespace mu::playback;
4545

4646
static const ActionCode PLAY_CODE("play");
47+
static const ActionCode PLAY_FROM_SELECTION("play-from-selection");
4748
static const ActionCode STOP_CODE("stop");
4849
static const ActionCode PAUSE_AND_SELECT_CODE("pause-and-select");
4950
static const ActionCode REWIND_CODE("rewind");
@@ -91,6 +92,7 @@ static std::string resolveAuxTrackTitle(aux_channel_idx_t index, const AudioOutp
9192
void PlaybackController::init()
9293
{
9394
dispatcher()->reg(this, PLAY_CODE, this, &PlaybackController::togglePlay);
95+
dispatcher()->reg(this, PLAY_FROM_SELECTION, this, &PlaybackController::playFromSelection);
9496
dispatcher()->reg(this, STOP_CODE, [this]() { PlaybackController::pause(/*select*/ false); });
9597
dispatcher()->reg(this, PAUSE_AND_SELECT_CODE, [this]() { PlaybackController::pause(/*select*/ true); });
9698
dispatcher()->reg(this, REWIND_CODE, this, &PlaybackController::rewind);
@@ -667,6 +669,38 @@ void PlaybackController::play()
667669
currentPlayer()->play(delay);
668670
}
669671

672+
void PlaybackController::playFromSelection()
673+
{
674+
if (selection()->isNone()) {
675+
return;
676+
}
677+
678+
int startTick = INT_MAX;
679+
for (const EngravingItem* item : selection()->elements()) {
680+
startTick = std::min(startTick, item->tick().ticks());
681+
}
682+
683+
const LoopBoundaries& loop = notationPlayback()->loopBoundaries();
684+
if (loop.enabled) {
685+
if (startTick < loop.loopInTick.ticks() || startTick > loop.loopOutTick.ticks()) {
686+
startTick = loop.loopInTick.ticks();
687+
}
688+
}
689+
690+
const RetVal<midi::tick_t> retval = notationPlayback()->playPositionTickByRawTick(startTick);
691+
if (!retval.ret) {
692+
return;
693+
}
694+
695+
seek(playedTickToSecs(retval.val));
696+
697+
if (isPaused()) {
698+
resume();
699+
} else if (!isPlaying()) {
700+
play();
701+
}
702+
}
703+
670704
void PlaybackController::rewind(const ActionData& args)
671705
{
672706
secs_t startSecs = playbackStartSecs();

0 commit comments

Comments
 (0)