Skip to content
Merged
2 changes: 1 addition & 1 deletion src/engraving/dom/cmd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1809,7 +1809,7 @@ void Score::changeCRlen(ChordRest* cr, const Fraction& dstF, bool fillWithRest)
connectTies();

if (elementToSelect) {
if (containsElement(elementToSelect)) {
if (canReselectItem(elementToSelect)) {
select(elementToSelect, SelectType::SINGLE, 0);
}
}
Expand Down
43 changes: 31 additions & 12 deletions src/engraving/dom/score.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1816,21 +1816,20 @@ void Score::doUndoRemoveElement(EngravingItem* element)
}
}

bool Score::containsElement(const EngravingItem* element) const
bool Score::canReselectItem(const EngravingItem* item) const
{
if (!element) {
if (!item || item->selected()) {
return false;
}

EngravingItem* parent = element->parentItem();
if (!parent) {
return false;
EngravingItem* seg = const_cast<EngravingItem*>(item->findAncestor(ElementType::SEGMENT));
if (seg) {
std::vector<EngravingItem*> elements;
seg->scanElements(&elements, collectElements, false /*all*/);
return muse::contains(elements, const_cast<EngravingItem*>(item));
}

std::vector<EngravingItem*> elements;
parent->scanElements(&elements, collectElements, false /*all*/);

return std::find(elements.cbegin(), elements.cend(), element) != elements.cend();
return true;
}

//---------------------------------------------------------
Expand Down Expand Up @@ -3219,7 +3218,7 @@ void Score::padToggle(Pad p, bool toggleForSelectionOnly)
}

for (const NoteVal& nval : m_is.notes()) {
if (chordContainsNoteVal(chord, nval)) {
if (chord && chord->findNote(nval.pitch)) {
continue;
}

Expand Down Expand Up @@ -3317,6 +3316,22 @@ void Score::padToggle(Pad p, bool toggleForSelectionOnly)
}
}

const int dots = m_is.duration().dots();

if (toggleForSelectionOnly && dots > 0 && !crs.empty()) {
bool shouldRemoveDots = true;
for (const ChordRest* cr : crs) {
if (dots != cr->dots()) {
shouldRemoveDots = false;
break;
}
}

if (shouldRemoveDots) {
m_is.setDots(0);
}
}

for (ChordRest* cr : crs) {
if (cr->isChord() && (toChord(cr)->isGrace())) {
//
Expand All @@ -3331,10 +3346,11 @@ void Score::padToggle(Pad p, bool toggleForSelectionOnly)
if (!elementsToSelect.empty()) {
std::vector<EngravingItem*> selectList;
for (EngravingItem* e : elementsToSelect) {
if (e && !e->selected()) {
if (canReselectItem(e)) {
selectList.push_back(e);
}
}

select(selectList, SelectType::ADD, 0);
selection().updateSelectedElements();
}
Expand All @@ -3343,8 +3359,11 @@ void Score::padToggle(Pad p, bool toggleForSelectionOnly)
m_is.setDuration(oldDuration);
m_is.setRest(oldRest);
m_is.setAccidentalType(oldAccidentalType);

if (noteEntryMode()) {
m_is.moveToNextInputPos();
if (m_is.lastSegment() == m_is.segment()) {
m_is.moveToNextInputPos();
}
}
}
}
Expand Down
3 changes: 2 additions & 1 deletion src/engraving/dom/score.h
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,6 @@ class Score : public EngravingObject, public muse::Injectable
void doUndoAddElement(EngravingItem*);
void removeElement(EngravingItem*);
void doUndoRemoveElement(EngravingItem*);
bool containsElement(const EngravingItem*) const;

Note* addPitch(NoteVal&, bool addFlag, InputState* externalInputState = nullptr);
Note* addMidiPitch(int pitch, bool addFlag, bool allowTransposition);
Expand Down Expand Up @@ -1085,6 +1084,8 @@ class Score : public EngravingObject, public muse::Injectable
void selectAdd(EngravingItem* e);
void selectRange(EngravingItem* e, staff_idx_t staffIdx);

bool canReselectItem(const EngravingItem* item) const;

bool trySelectSimilarInRange(EngravingItem* e);
bool tryExtendSingleSelectionToRange(EngravingItem* e, staff_idx_t staffIdx);

Expand Down
15 changes: 0 additions & 15 deletions src/engraving/dom/utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1708,19 +1708,4 @@ bool segmentsAreAdjacentInRepeatStructure(const Segment* firstSeg, const Segment

return true;
}

bool chordContainsNoteVal(const Chord* chord, const NoteVal& nval)
{
if (!chord) {
return false;
}

for (const Note* note : chord->notes()) {
if (note->noteVal() == nval) {
return true;
}
}

return false;
}
}
2 changes: 0 additions & 2 deletions src/engraving/dom/utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,4 @@ extern std::vector<Measure*> findFollowingRepeatMeasures(const Measure* measure)
extern std::vector<Measure*> findPreviousRepeatMeasures(const Measure* measure);
extern bool repeatHasPartialLyricLine(const Measure* endRepeatMeasure);
extern bool segmentsAreAdjacentInRepeatStructure(const Segment* firstSeg, const Segment* secondSeg);

extern bool chordContainsNoteVal(const Chord* chord, const NoteVal& nval);
} // namespace mu::engraving
4 changes: 3 additions & 1 deletion src/engraving/playback/playbackmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -717,7 +717,9 @@ void PlaybackModel::clearExpiredEvents(const int tickFrom, const int tickTo, con
int removeEventsFromTick = std::max(tickFrom, repeatStartTick);
timestamp_t removeEventsFrom = timestampFromTicks(m_score, removeEventsFromTick + tickPositionOffset);

int removeEventsToTick = std::min(tickTo, repeatEndTick);
//! NOTE: the end tick of the current repeat segment == the start tick of the next repeat segment
//! so subtract 1 to avoid removing events belonging to the next segment
int removeEventsToTick = std::min(tickTo, repeatEndTick - 1);
timestamp_t removeEventsTo = timestampFromTicks(m_score, removeEventsToTick + tickPositionOffset);

removeEventsFromRange(trackFrom, trackTo, removeEventsFrom, removeEventsTo);
Expand Down
15 changes: 13 additions & 2 deletions src/engraving/tests/playback/playbackmodel_tests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -845,22 +845,33 @@ TEST_F(Engraving_PlaybackModelTests, SimpleRepeat_Changes_Notification)
model.load(score);

PlaybackData result = model.resolveTrackPlaybackData(part->id(), part->instrumentId());
EXPECT_EQ(result.originEvents.size(), expectedChangedEventsCount);

// [THEN] Updated events map will match our expectations
result.mainStream.onReceive(this, [expectedChangedEventsCount](const PlaybackEventsMap& updatedEvents, const DynamicLevelLayers&,
const PlaybackParamLayers&) {
EXPECT_EQ(updatedEvents.size(), expectedChangedEventsCount);
});

// [WHEN] Notation has been changed
// [WHEN] Score has been changed: the range starts ouside the repeat and ends inside it
ScoreChangesRange range;
range.tickFrom = 480; // 2nd note of the 1st measure
range.tickFrom = 480; // 2nd note of the 1st measure (outside the repeat)
range.tickTo = 3840; // 1st note of the 3rd measure (inside the repeat)
range.staffIdxFrom = 0;
range.staffIdxTo = 0;
range.changedTypes = { ElementType::NOTE };

score->changesChannel().send(range);

// [WHEN] Score has been changed: the range is inside the repeat and tickTo == the end tick of the repeat
// See: https://github.com/musescore/MuseScore/issues/25899
range.tickFrom = 4800; // 3rd note of the 3rd measure (inside the repeat)
range.tickTo = 5760; // end tick of the repeat
range.staffIdxFrom = 0;
range.staffIdxTo = 0;
range.changedTypes = { ElementType::PEDAL };

score->changesChannel().send(range);
}

/**
Expand Down
9 changes: 9 additions & 0 deletions src/framework/audio/audioutils.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ inline String audioSourceName(const AudioInputParams& params)
return String::fromStdString(params.resourceMeta.id);
}

inline String audioSourcePackName(const AudioInputParams& params)
{
if (params.type() == AudioSourceType::MuseSampler) {
return params.resourceMeta.attributeVal(u"musePack");
}

return String();
}

inline String audioSourceCategoryName(const AudioInputParams& params)
{
if (params.type() == AudioSourceType::MuseSampler) {
Expand Down
1 change: 1 addition & 0 deletions src/framework/shortcuts/view/mididevicemappingmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ inline ActionCodeList allMidiActions()
"pad-note-32",
"pad-note-64",
"undo",
"rest",
"pad-rest",
"tie",
"pad-dot",
Expand Down
2 changes: 1 addition & 1 deletion src/framework/vst/internal/vstplugininstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ class VstPluginInstance : public IVstPluginInstance, public async::Asyncable

async::Notification loadingCompleted() const override;

async::Channel<muse::audio::AudioUnitConfig> pluginSettingsChanged() const;
async::Channel<muse::audio::AudioUnitConfig> pluginSettingsChanged() const override;

private:
void rescanParams();
Expand Down
4 changes: 2 additions & 2 deletions src/instrumentsscene/view/layoutpaneltreemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,8 +455,6 @@ void LayoutPanelTreeModel::addSystemMarkings()
if (const Staff* staff = resolveNewSystemObjectStaff()) {
m_masterNotation->parts()->addSystemObjects({ staff->id() });
}

updateIsAddingSystemMarkingsAvailable();
}

void LayoutPanelTreeModel::moveSelectedRowsUp()
Expand Down Expand Up @@ -1104,6 +1102,8 @@ void LayoutPanelTreeModel::updateSystemObjectLayers()
break;
}
}

updateIsAddingSystemMarkingsAvailable();
}

const PartTreeItem* LayoutPanelTreeModel::findPartItemByStaff(const Staff* staff) const
Expand Down
12 changes: 12 additions & 0 deletions src/notation/internal/notationinteraction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5053,6 +5053,18 @@ void NotationInteraction::putRestToSelection()

if (is.usingNoteEntryMethod(NoteEntryMethod::BY_DURATION) || is.usingNoteEntryMethod(NoteEntryMethod::RHYTHM)) {
m_noteInput->padNote(Pad::REST);
} else if (is.usingNoteEntryMethod(NoteEntryMethod::REPITCH)) {
ChordRest* cr = is.cr();
if (cr) {
TDuration duration = cr->durationType();
if (duration.isValid() && !duration.isZero()) {
if (duration.isMeasure()) {
is.moveToNextInputPos();
} else {
putRest(duration);
}
}
}
} else {
putRest(is.duration());
}
Expand Down
9 changes: 8 additions & 1 deletion src/notation/internal/notationnoteinput.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -855,7 +855,14 @@ void NotationNoteInput::updateInputState()
{
TRACEFUNC;

score()->inputState().update(score()->selection());
NoteInputState& is = score()->inputState();
is.update(score()->selection());

if (!configuration()->addAccidentalDotsArticulationsToNextNoteEntered()) {
is.setAccidentalType(AccidentalType::NONE);
is.setDots(0);
is.setArticulationIds({});
}

notifyAboutStateChanged();
}
Expand Down
3 changes: 2 additions & 1 deletion src/notation/internal/notationuiactions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1109,7 +1109,8 @@ const UiActionList NotationUiActions::m_actions = {
mu::context::UiCtxProjectOpened,
mu::context::CTX_NOTATION_NOT_NOTE_INPUT_STAFF_TAB,
TranslatableString("action", "Rest"),
TranslatableString("action", "Enter rest")
TranslatableString("action", "Enter rest"),
IconCode::Code::REST
),
UiAction("rest-TAB",
mu::context::UiCtxProjectOpened,
Expand Down
18 changes: 14 additions & 4 deletions src/notation/view/percussionpanel/percussionpanelmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -357,15 +357,25 @@ void PercussionPanelModel::updateSoundTitle(const InstrumentTrackId& trackId)
}

const audio::AudioInputParams& params = audioSettings()->trackInputParams(trackId);

const QString name = muse::audio::audioSourceName(params).toQString();
const QString category = muse::audio::audioSourceCategoryName(params).toQString();
if (name.isEmpty() || category.isEmpty()) {
if (name.isEmpty()) {
setSoundTitle(QString());
return;
}

setSoundTitle(category + ": " + name);
const QString pack = muse::audio::audioSourcePackName(params).toQString();
if (!pack.isEmpty() && pack != name) {
setSoundTitle(pack + ": " + name);
return;
}

const QString category = muse::audio::audioSourceCategoryName(params).toQString();
if (!category.isEmpty() && category != name) {
setSoundTitle(category + ": " + name);
return;
}

setSoundTitle(name);
}

bool PercussionPanelModel::eventFilter(QObject* watched, QEvent* event)
Expand Down
5 changes: 2 additions & 3 deletions src/notation/view/percussionpanel/percussionpanelmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,10 +77,7 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus
explicit PercussionPanelModel(QObject* parent = nullptr);

bool enabled() const;
void setEnabled(bool enabled);

QString soundTitle() const;
void setSoundTitle(const QString& soundTitle);

PanelMode::Mode currentPanelMode() const;
void setCurrentPanelMode(const PanelMode::Mode& panelMode);
Expand Down Expand Up @@ -117,9 +114,11 @@ class PercussionPanelModel : public QObject, public muse::Injectable, public mus
private:
void setUpConnections();

void setEnabled(bool enabled);
void setDrumset(mu::engraving::Drumset* drumset);

void updateSoundTitle(const InstrumentTrackId& trackId);
void setSoundTitle(const QString& soundTitle);

bool eventFilter(QObject* watched, QEvent* event) override;

Expand Down
2 changes: 1 addition & 1 deletion src/playback/view/playbacktoolbarmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ MenuItem* PlaybackToolBarModel::makeInputPitchMenu()
items << makeMenuItem(action.code);
}

MenuItem* menu = makeMenu(muse::TranslatableString("notation", "Input pitch"), items);
MenuItem* menu = makeMenu(muse::TranslatableString("notation", "MIDI input pitch"), items);
UiAction action = menu->action();
action.iconCode = IconCode::Code::MUSIC_NOTES;
menu->setAction(action);
Expand Down
Loading