Skip to content

Commit 8379df9

Browse files
Merge pull request #29891 from RomanPudashkin/play_from_selection
Add "Play from selection" shortcut
2 parents d49d204 + c89d560 commit 8379df9

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
@@ -1132,10 +1132,8 @@ void NotationInteraction::clearSelection()
11321132
{
11331133
TRACEFUNC;
11341134

1135-
if (isElementEditStarted()) {
1135+
if (isEditingElement()) {
11361136
endEditElement();
1137-
} else if (m_editData.element) {
1138-
m_editData.element = nullptr;
11391137
}
11401138

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

1300-
m_dragData.ed.isEditMode = isElementEditStarted();
1298+
m_dragData.ed.isEditMode = isEditingElement();
13011299

13021300
if (isTextEditingStarted()) {
13031301
m_editData.pos = toPos;
@@ -3768,7 +3766,7 @@ void NotationInteraction::addToSelection(MoveDirection d, MoveSelectionType type
37683766
bool NotationInteraction::moveSelectionAvailable(MoveSelectionType type) const
37693767
{
37703768
if (type != MoveSelectionType::EngravingItem) {
3771-
return !isElementEditStarted();
3769+
return !isEditingElement();
37723770
}
37733771

37743772
EngravingItem* el = score()->selection().element();
@@ -3786,7 +3784,7 @@ bool NotationInteraction::moveSelectionAvailable(MoveSelectionType type) const
37863784
return true;
37873785
}
37883786

3789-
return m_editData.element && m_editData.element->isTextBase() ? !isTextEditingStarted() : !isElementEditStarted();
3787+
return m_editData.element && m_editData.element->isTextBase() ? !isTextEditingStarted() : !isEditingElement();
37903788
}
37913789

37923790
void NotationInteraction::moveSelection(MoveDirection d, MoveSelectionType type)
@@ -4100,7 +4098,7 @@ void NotationInteraction::moveElementSelection(MoveDirection d)
41004098
return;
41014099
}
41024100

4103-
if (isElementEditStarted()) {
4101+
if (isEditingElement()) {
41044102
endEditElement();
41054103
}
41064104

@@ -4309,6 +4307,7 @@ void NotationInteraction::startEditText(EngravingItem* element, const PointF& cu
43094307

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

4310+
m_isEditingElementChanged.notify();
43124311
notifyAboutTextEditingStarted();
43134312
notifyAboutTextEditingChanged();
43144313
}
@@ -4449,6 +4448,8 @@ void NotationInteraction::endEditText()
44494448

44504449
TextBase* editedElement = toTextBase(m_editData.element);
44514450
doEndEditElement();
4451+
4452+
m_isEditingElementChanged.notify();
44524453
notifyAboutTextEditingEnded(editedElement);
44534454

44544455
notifyAboutTextEditingChanged();
@@ -4623,7 +4624,7 @@ void NotationInteraction::updateDragAnchorLines()
46234624
setAnchorLines(anchorLines);
46244625
}
46254626

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

4637-
if (isElementEditStarted()) {
4638+
if (isEditingElement()) {
46384639
return;
46394640
}
46404641

@@ -4646,6 +4647,8 @@ void NotationInteraction::startEditElement(EngravingItem* element)
46464647
element->startEdit(m_editData);
46474648
m_editData.element = element;
46484649
}
4650+
4651+
m_isEditingElementChanged.notify();
46494652
}
46504653

46514654
void NotationInteraction::changeEditElement(EngravingItem* newElement)
@@ -4795,9 +4798,15 @@ void NotationInteraction::endEditElement()
47954798
doEndEditElement();
47964799
resetAnchorLines();
47974800

4801+
m_isEditingElementChanged.notify();
47984802
notifyAboutNotationChanged();
47994803
}
48004804

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

64176426
bool NotationInteraction::needEndElementEditing(const std::vector<EngravingItem*>& newSelectedElements) const
64186427
{
6419-
if (!isElementEditStarted()) {
6428+
if (!isEditingElement()) {
64206429
return false;
64216430
}
64226431

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;
@@ -538,6 +539,8 @@ class NotationInteraction : public INotationInteraction, public muse::Injectable
538539

539540
mu::engraving::EditData m_editData;
540541

542+
muse::async::Notification m_isEditingElementChanged;
543+
541544
muse::async::Notification m_textEditingStarted;
542545
muse::async::Notification m_textEditingChanged;
543546
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)