diff --git a/src/engraving/api/v1/cursor.cpp b/src/engraving/api/v1/cursor.cpp
index 501e7fead85aa..e7d0738572ce2 100644
--- a/src/engraving/api/v1/cursor.cpp
+++ b/src/engraving/api/v1/cursor.cpp
@@ -363,7 +363,8 @@ void Cursor::add(EngravingItem* wrapped)
s->setParent(curElement);
m_score->undoAddElement(s);
}
- } // FALLTHROUGH
+ [[fallthrough]];
+ }
case ElementType::FINGERING:
case ElementType::BEND:
case ElementType::NOTEHEAD: {
diff --git a/src/engraving/data/harmony_to_diagram.xml b/src/engraving/data/harmony_to_diagram.xml
index b44eaaa3d3036..65e7a2745a4a2 100644
--- a/src/engraving/data/harmony_to_diagram.xml
+++ b/src/engraving/data/harmony_to_diagram.xml
@@ -33782,14 +33782,14 @@
circle
- circle
+ normal
circle
- O[2-O][2-O]OOO
+ O[2-O][2-O]O[2-O]O
c#m7b5/e
diff --git a/src/engraving/dom/anchors.cpp b/src/engraving/dom/anchors.cpp
index 3886ec099ac24..8b72e731ee27f 100644
--- a/src/engraving/dom/anchors.cpp
+++ b/src/engraving/dom/anchors.cpp
@@ -158,18 +158,17 @@ void MoveElementAnchors::moveElementAnchors(EngravingItem* element, KeyboardKey
return;
}
- bool leftRightKey = key == Key_Left || key == Key_Right;
bool altMod = mod & AltModifier;
- bool shiftMod = mod & ShiftModifier;
- bool changeAnchorType = shiftMod && altMod && leftRightKey && canAnchorToEndOfPrevious(element);
bool anchorToEndOfPrevious = element->getProperty(Pid::ANCHOR_TO_END_OF_PREVIOUS).toBool();
- if (changeAnchorType) {
+ bool changeAnchorType = altMod && canAnchorToEndOfPrevious(element);
+ bool resetAnchorType = !altMod && anchorToEndOfPrevious;
+ if (changeAnchorType || resetAnchorType) {
element->undoChangeProperty(Pid::ANCHOR_TO_END_OF_PREVIOUS, !anchorToEndOfPrevious,
element->propertyFlags(Pid::ANCHOR_TO_END_OF_PREVIOUS));
- bool doesntNeedMoveSeg = ((key == Key_Left && anchorToEndOfPrevious) || (key == Key_Right && !anchorToEndOfPrevious));
- if (doesntNeedMoveSeg) {
+ bool needMoveSeg = (key == Key_Left && anchorToEndOfPrevious) || (key == Key_Right && !anchorToEndOfPrevious);
+ if (!needMoveSeg) {
checkMeasureBoundariesAndMoveIfNeed(element);
return;
}
@@ -199,7 +198,7 @@ void MoveElementAnchors::checkMeasureBoundariesAndMoveIfNeed(EngravingItem* elem
Measure* curMeasure = curSeg->measure();
Measure* prevMeasure = curMeasure->prevMeasure();
bool anchorToEndOfPrevious = element->getProperty(Pid::ANCHOR_TO_END_OF_PREVIOUS).toBool();
- bool needMoveToNext = curTick == curMeasure->endTick() && anchorToEndOfPrevious;
+ bool needMoveToNext = curTick == curMeasure->endTick() && !anchorToEndOfPrevious;
bool needMoveToPrevious = curSeg->rtick().isZero() && anchorToEndOfPrevious && prevMeasure;
if (!needMoveToPrevious && !needMoveToNext) {
@@ -251,14 +250,6 @@ void MoveElementAnchors::moveElementAnchorsOnDrag(EngravingItem* element, EditDa
void MoveElementAnchors::moveSegment(EngravingItem* element, bool forward)
{
- if (canAnchorToEndOfPrevious(element)) {
- bool cachedAnchorToEndOfPrevious = element->getProperty(Pid::ANCHOR_TO_END_OF_PREVIOUS).toBool();
- element->undoResetProperty(Pid::ANCHOR_TO_END_OF_PREVIOUS);
- if (cachedAnchorToEndOfPrevious && forward) {
- return;
- }
- }
-
Segment* curSeg = toSegment(element->parentItem());
Segment* newSeg = getNewSegment(element, curSeg, forward);
diff --git a/src/engraving/dom/box.cpp b/src/engraving/dom/box.cpp
index fbdea04f6c8ec..5a636f6be4361 100644
--- a/src/engraving/dom/box.cpp
+++ b/src/engraving/dom/box.cpp
@@ -706,6 +706,9 @@ FBox::FBox(System* parent)
resetProperty(Pid::BOTTOM_MARGIN);
resetProperty(Pid::TOP_GAP);
resetProperty(Pid::BOTTOM_GAP);
+ resetProperty(Pid::EXCLUDE_FROM_OTHER_PARTS);
+ resetProperty(Pid::APPEARANCE_LINKED_TO_MASTER);
+ resetProperty(Pid::POSITION_LINKED_TO_MASTER);
}
void FBox::init()
@@ -722,7 +725,7 @@ void FBox::init()
StringList diagramsNamesInScore;
std::vector harmonyOrDiagramsInScore;
- for (mu::engraving::Segment* segment = masterScore()->firstSegment(mu::engraving::SegmentType::ChordRest); segment;
+ for (mu::engraving::Segment* segment = score()->firstSegment(mu::engraving::SegmentType::ChordRest); segment;
segment = segment->next1(mu::engraving::SegmentType::ChordRest)) {
for (EngravingItem* item : segment->annotations()) {
if (!item || !item->part()) {
@@ -749,6 +752,8 @@ void FBox::init()
}
}
+ m_diagramsOrderInScore = diagramsNamesInScore;
+
for (size_t i = 0; i < oldDiagramsNames.size(); ++i) {
String oldName = oldDiagramsNames[i];
if (!muse::contains(diagramsNamesInScore, oldName)) {
@@ -766,19 +771,6 @@ void FBox::init()
score()->undo(new AddFretDiagramToFretBox(newDiagram, idx));
}
}
-
- StringList currentDiagrams;
- for (EngravingItem* item : el()) {
- currentDiagrams.push_back(toFretDiagram(item)->harmonyText().toLower());
- }
-
- if (!m_invisibleDiagrams.empty()) {
- updateInvisibleDiagrams(currentDiagrams);
- }
-
- if (!m_diagramsOrder.empty()) {
- updateDiagramsOrder(currentDiagrams);
- }
}
void FBox::add(EngravingItem* e)
@@ -848,9 +840,7 @@ PropertyValue FBox::getProperty(Pid propertyId) const
case Pid::RIGHT_MARGIN:
return m_contentAlignmentH == AlignH::RIGHT ? VBox::getProperty(propertyId) : PropertyValue();
case Pid::FRET_FRAME_DIAGRAMS_ORDER:
- return !m_diagramsOrder.empty() ? m_diagramsOrder.join(FRET_BOX_DIAGRAMS_SEPARATOR) : PropertyValue();
- case Pid::FRET_FRAME_INVISIBLE_DIAGRAMS:
- return !m_invisibleDiagrams.empty() ? m_invisibleDiagrams.join(FRET_BOX_DIAGRAMS_SEPARATOR) : PropertyValue();
+ return diagramsOrder().join(FRET_BOX_DIAGRAMS_SEPARATOR);
default:
return VBox::getProperty(propertyId);
}
@@ -880,10 +870,7 @@ bool FBox::setProperty(Pid propertyId, const PropertyValue& val)
resetProperty(Pid::RIGHT_MARGIN);
break;
case Pid::FRET_FRAME_DIAGRAMS_ORDER:
- m_diagramsOrder = val.value().split(FRET_BOX_DIAGRAMS_SEPARATOR);
- break;
- case Pid::FRET_FRAME_INVISIBLE_DIAGRAMS:
- m_invisibleDiagrams = val.value().split(FRET_BOX_DIAGRAMS_SEPARATOR);
+ reorderElements(val.value().split(FRET_BOX_DIAGRAMS_SEPARATOR));
break;
default:
return VBox::setProperty(propertyId, val);
@@ -907,9 +894,12 @@ PropertyValue FBox::propertyDefault(Pid propertyId) const
case Pid::FRET_FRAME_H_ALIGN:
return static_cast(AlignH::HCENTER);
case Pid::FRET_FRAME_DIAGRAMS_ORDER:
- return PropertyValue();
- case Pid::FRET_FRAME_INVISIBLE_DIAGRAMS:
- return PropertyValue();
+ return m_diagramsOrderInScore.join(FRET_BOX_DIAGRAMS_SEPARATOR);
+ case Pid::EXCLUDE_FROM_OTHER_PARTS:
+ return true;
+ case Pid::APPEARANCE_LINKED_TO_MASTER:
+ case Pid::POSITION_LINKED_TO_MASTER:
+ return false;
default:
return VBox::propertyDefault(propertyId);
}
@@ -946,81 +936,25 @@ void FBox::undoReorderElements(const StringList& newOrder)
triggerLayout();
}
-ElementList FBox::orderedElements(bool includeInvisible) const
+void FBox::reorderElements(const StringList& newOrder)
{
- ElementList elements = el();
- const StringList& diagramsOrder = this->diagramsOrder();
- if (diagramsOrder.empty()) {
- return elements;
- }
-
- std::sort(elements.begin(), elements.end(), [&diagramsOrder](const EngravingItem* a, const EngravingItem* b) {
- const FretDiagram* diagramA = toFretDiagram(a);
- const String diagramAHarmonyName = diagramA->harmonyText().toLower();
-
- const FretDiagram* diagramB = toFretDiagram(b);
- const String diagramBHarmonyName = diagramB->harmonyText().toLower();
-
- auto itA = std::find(diagramsOrder.begin(), diagramsOrder.end(), diagramAHarmonyName);
- auto itB = std::find(diagramsOrder.begin(), diagramsOrder.end(), diagramBHarmonyName);
-
- return itA < itB;
+ std::sort(m_el.begin(), m_el.end(), [&](EngravingItem* a, EngravingItem* b) {
+ String nameA = toFretDiagram(a)->harmonyText().toLower();
+ String nameB = toFretDiagram(b)->harmonyText().toLower();
+ auto iterA = std::find(newOrder.begin(), newOrder.end(), nameA);
+ auto iterB = std::find(newOrder.begin(), newOrder.end(), nameB);
+ return iterA < iterB;
});
-
- if (!includeInvisible) {
- const StringList& invisibleDiagrams = this->invisibleDiagrams();
-
- muse::remove_if(elements, [&invisibleDiagrams](const EngravingItem* element){
- const FretDiagram* diagram = toFretDiagram(element);
- const String diagramHarmonyName = diagram->harmonyText().toLower();
- return muse::contains(invisibleDiagrams, diagramHarmonyName);
- });
- }
-
- return elements;
}
-void FBox::undoSetInvisibleDiagrams(const StringList& invisibleDiagrams)
+StringList FBox::diagramsOrder() const
{
- StringList diagrams;
- for (const String& harmonyName : invisibleDiagrams) {
- diagrams.push_back(harmonyName.toLower());
- }
-
- undoChangeProperty(Pid::FRET_FRAME_INVISIBLE_DIAGRAMS, diagrams.join(FRET_BOX_DIAGRAMS_SEPARATOR));
- triggerLayout();
-}
-
-void FBox::updateDiagramsOrder(const StringList& currentDiagrams)
-{
- if (currentDiagrams == m_diagramsOrder) {
- return;
- }
-
- m_diagramsOrder.erase(std::remove_if(m_diagramsOrder.begin(), m_diagramsOrder.end(),
- [&](const String& harmonyName) { return !muse::contains(currentDiagrams, harmonyName); }),
- m_diagramsOrder.end());
-
- String previousHarmonyName;
- for (const String& harmonyName : currentDiagrams) {
- if (!muse::contains(m_diagramsOrder, harmonyName)) {
- size_t index = 0;
- if (!previousHarmonyName.empty()) {
- index = std::find(m_diagramsOrder.begin(), m_diagramsOrder.end(), previousHarmonyName) - m_diagramsOrder.begin() + 1;
- }
-
- m_diagramsOrder.insert(m_diagramsOrder.begin() + index, harmonyName);
- }
-
- previousHarmonyName = harmonyName;
+ StringList result;
+ for (EngravingItem* item : m_el) {
+ result.push_back(toFretDiagram(item)->harmonyText().toLower());
}
-}
-void FBox::updateInvisibleDiagrams(const StringList& currentDiagrams)
-{
- m_invisibleDiagrams.erase(std::remove_if(m_invisibleDiagrams.begin(), m_invisibleDiagrams.end(),
- [&](const String& harmonyName) { return !muse::contains(currentDiagrams, harmonyName); }),
- m_invisibleDiagrams.end());
+ return result;
}
//---------------------------------------------------------
diff --git a/src/engraving/dom/box.h b/src/engraving/dom/box.h
index 56c31ef8c540e..e6a6ed1ab5758 100644
--- a/src/engraving/dom/box.h
+++ b/src/engraving/dom/box.h
@@ -208,19 +208,14 @@ class FBox : public VBox
std::vector gripsPositions(const EditData&) const override;
void undoReorderElements(const StringList& newOrder);
- const StringList& diagramsOrder() const { return m_diagramsOrder; }
-
- void undoSetInvisibleDiagrams(const StringList& invisibleDiagrams);
- const StringList& invisibleDiagrams() const { return m_invisibleDiagrams; }
-
- ElementList orderedElements(bool includeInvisible = false) const;
+ void reorderElements(const StringList& newOrder);
+ StringList diagramsOrder() const;
bool needsRebuild() const { return m_needsRebuild; }
void setNeedsRebuild(bool v) { m_needsRebuild = v; }
private:
- void updateDiagramsOrder(const StringList& currentDiagrams);
void updateInvisibleDiagrams(const StringList& currentDiagrams);
size_t computeInsertionIdx(const String& nameOfDiagramBeforeThis);
@@ -234,8 +229,7 @@ class FBox : public VBox
AlignH m_contentAlignmentH = AlignH::HCENTER;
- StringList /*harmonyNames*/ m_diagramsOrder;
- StringList /*harmonyNames*/ m_invisibleDiagrams;
+ StringList m_diagramsOrderInScore;
};
//---------------------------------------------------------
diff --git a/src/engraving/dom/chordlist.cpp b/src/engraving/dom/chordlist.cpp
index 9b6be0905f77c..cb40bb3129ded 100644
--- a/src/engraving/dom/chordlist.cpp
+++ b/src/engraving/dom/chordlist.cpp
@@ -1707,7 +1707,6 @@ const std::list& ParsedChord::renderList(const ChordList* cl,
// Jazz superscript
if (superScriptModifier) {
// Set scale
- LOGI() << "SCALE: " << cl->stackedModifierMag();
m_renderList.emplace_back(new RenderActionScale(cl->stackedModifierMag()));
// Move to x-height
m_renderList.emplace_back(new RenderActionPush());
diff --git a/src/engraving/dom/edit.cpp b/src/engraving/dom/edit.cpp
index 9e17cdebddf4f..1a06a598789c3 100644
--- a/src/engraving/dom/edit.cpp
+++ b/src/engraving/dom/edit.cpp
@@ -3886,37 +3886,6 @@ void Score::cmdDeleteSelection()
// so we don't try to delete them twice if they are also in selection
std::set deletedSpanners;
- // diagrams in the fret box must be processed first than diagrams outside the box,
- // which causes the fret box to be rebuilt and all elements inside to be deleted
- std::sort(el.begin(), el.end(), [&](const EngravingItem* item1, const EngravingItem* item2) {
- bool inBox1 = isElementInFretBox(item1);
- bool inBox2 = isElementInFretBox(item2);
-
- return inBox1 == inBox2 ? false : inBox1;
- });
-
- // if there is harmony or fret diagram outside the fret box
- // then the fret box will be rebuilt and we should exclude fret box's elements
- bool hasHarmonyOrFretDiagramsInFretBox = false;
- bool hasHarmonyOrFretDiagramsOutFretBox = false;
- for (const EngravingItem* element : el) {
- if (!element->isFretDiagram() && !element->isHarmony()) {
- continue;
- }
-
- if (isElementInFretBox(element)) {
- hasHarmonyOrFretDiagramsInFretBox = true;
- } else {
- hasHarmonyOrFretDiagramsOutFretBox = true;
- }
-
- if (hasHarmonyOrFretDiagramsInFretBox && hasHarmonyOrFretDiagramsOutFretBox) {
- break;
- }
- }
-
- bool willFretBoxBeRebuilded = hasHarmonyOrFretDiagramsInFretBox && hasHarmonyOrFretDiagramsOutFretBox;
-
auto selectCRAtTickAndTrack = [this, &crsSelectedAfterDeletion](Fraction tick, track_idx_t track) {
ChordRest* cr = findCR(tick, track);
if (cr) {
@@ -3988,64 +3957,26 @@ void Score::cmdDeleteSelection()
continue;
}
- // We can't delete elements inside fret box, instead we hide them
if (e->isFretDiagram() || e->isHarmony()) {
- auto excludeElementFromSelectionInfo = [this](EngravingItem* element) {
- // we need to exclude elements ftom undo stack selection info,
- // so that when trying to return the selection there is no crash
- UndoMacro* activeCommand = undoStack()->activeCommand();
- activeCommand->excludeElementFromSelectionInfo(element);
- };
-
- if (willFretBoxBeRebuilded && isElementInFretBox(e)) {
- excludeElementFromSelectionInfo(e);
- continue;
- }
-
- auto hideDiagramInFretBox = [&excludeElementFromSelectionInfo](FBox* fbox, EngravingItem* element){
- StringList invisibleDiagrams = fbox->invisibleDiagrams();
- const String harmonyName = element->isFretDiagram() ? toFretDiagram(element)->harmony()->harmonyName().toLower()
- : toHarmony(element)->harmonyName().toLower();
-
- invisibleDiagrams.push_back(harmonyName);
- fbox->undoSetInvisibleDiagrams(invisibleDiagrams);
-
- excludeElementFromSelectionInfo(element);
- };
-
- if (e->isFretDiagram() && toFretDiagram(e)->isInFretBox()) {
- FBox* fbox = toFBox(e->explicitParent());
- hideDiagramInFretBox(fbox, toFretDiagram(e));
- elSelectedAfterDeletion = fbox;
- continue;
- } else if (e->isHarmony()) {
- EngravingObject* parent = toHarmony(e)->explicitParent();
- FretDiagram* fretDiagram = parent->isFretDiagram() ? toFretDiagram(parent) : nullptr;
-
- if (fretDiagram && fretDiagram->isInFretBox()) {
- FBox* fbox = toFBox(fretDiagram->explicitParent());
- hideDiagramInFretBox(fbox, fretDiagram);
- elSelectedAfterDeletion = fbox;
+ FBox* fbox = toFBox(e->findAncestor(ElementType::FBOX));
+ if (fbox) {
+ // We can't delete elements inside fret box, instead we hide them
+ if (FretDiagram* fretDiagram = e->isFretDiagram() ? toFretDiagram(e) : toFretDiagram(e->parent())) {
+ fretDiagram->undoChangeProperty(Pid::VISIBLE, false);
continue;
}
- }
- }
-
- if (e->isFretDiagram()) {
- FretDiagram* fretDiagram = toFretDiagram(e);
- Harmony* harmony = fretDiagram->harmony();
- if (harmony) {
- undo(new FretLinkHarmony(fretDiagram, harmony, true /* unlink */));
- elSelectedAfterDeletion = fretDiagram->segment()->findAnnotation(ElementType::HARMONY,
- fretDiagram->track(),
- fretDiagram->track());
- }
- }
-
- if (e->isHarmony()) {
- Harmony* harmony = toHarmony(e);
- if (harmony->parentItem()->isFretDiagram()) {
- elSelectedAfterDeletion = harmony->parentItem();
+ } else if (e->isFretDiagram()) {
+ FretDiagram* fretDiagram = toFretDiagram(e);
+ Harmony* harmony = fretDiagram->harmony();
+ if (harmony) {
+ undo(new FretLinkHarmony(fretDiagram, harmony, true /* unlink */));
+ elSelectedAfterDeletion = harmony;
+ }
+ } else if (e->isHarmony()) {
+ Harmony* harmony = toHarmony(e);
+ if (harmony->parentItem()->isFretDiagram()) {
+ elSelectedAfterDeletion = harmony->parentItem();
+ }
}
}
@@ -7047,7 +6978,7 @@ void Score::undoAddElement(EngravingItem* element, bool addToLinkedStaves, bool
// make harmony child of fret diagram if possible
if (ne->isHarmony()) {
for (EngravingItem* segel : segment->annotations()) {
- if (segel && segel->isFretDiagram() && segel->track() == linkedTrack) {
+ if (segel && segel->isFretDiagram() && segel->track() == linkedTrack && !toFretDiagram(segel)->harmony()) {
segel->add(ne);
break;
}
diff --git a/src/engraving/dom/harmony.cpp b/src/engraving/dom/harmony.cpp
index c9c050a160710..d1341862ef5d3 100644
--- a/src/engraving/dom/harmony.cpp
+++ b/src/engraving/dom/harmony.cpp
@@ -1527,6 +1527,7 @@ bool Harmony::setProperty(Pid pid, const PropertyValue& v)
}
score()->rebuildFretBox();
}
+ break;
}
default:
return TextBase::setProperty(pid, v);
diff --git a/src/engraving/dom/measure.cpp b/src/engraving/dom/measure.cpp
index 8c4f9a4755958..e5b1935feefa6 100644
--- a/src/engraving/dom/measure.cpp
+++ b/src/engraving/dom/measure.cpp
@@ -1766,8 +1766,12 @@ EngravingItem* Measure::drop(EditData& data)
score()->insertBox(ElementType::TBOX, this);
break;
case ActionIconType::FFRAME:
- score()->insertBox(ElementType::FBOX, this);
+ {
+ Score::InsertMeasureOptions options;
+ options.cloneBoxToAllParts = false;
+ score()->insertBox(ElementType::FBOX, this, options);
break;
+ }
case ActionIconType::MEASURE:
score()->insertMeasure(ElementType::MEASURE, this);
break;
diff --git a/src/engraving/dom/page.cpp b/src/engraving/dom/page.cpp
index 00a1aefe4b857..72d5e2127be2c 100644
--- a/src/engraving/dom/page.cpp
+++ b/src/engraving/dom/page.cpp
@@ -394,12 +394,12 @@ TextBlock Page::replaceTextMacros(const TextBlock& tb) const
if (!m_no) {
break;
}
- // FALLTHROUGH
+ [[fallthrough]];
case 'N': // on page 1 only if there are multiple pages
if ((score()->npages() + score()->pageNumberOffset()) <= 1) {
break;
}
- // FALLTHROUGH
+ [[fallthrough]];
case 'P': // on all pages
{
int no = static_cast(m_no) + 1 + score()->pageNumberOffset();
@@ -426,7 +426,7 @@ TextBlock Page::replaceTextMacros(const TextBlock& tb) const
if (!m_no) {
break;
}
- // FALLTHROUGH
+ [[fallthrough]];
case 'I':
newFragments.back().text += score()->metaTag(u"partName");
break;
@@ -471,7 +471,7 @@ TextBlock Page::replaceTextMacros(const TextBlock& tb) const
if (m_no) {
break;
}
- // FALLTHROUGH
+ [[fallthrough]];
case 'c':
{
const String copyrightString = score()->metaTag(u"copyright");
diff --git a/src/engraving/dom/pitchspelling.cpp b/src/engraving/dom/pitchspelling.cpp
index 17ef621d522fc..e1dfbac5cbe5a 100644
--- a/src/engraving/dom/pitchspelling.cpp
+++ b/src/engraving/dom/pitchspelling.cpp
@@ -747,11 +747,11 @@ void Score::spellNotelist(std::vector& notes)
case 3:
k = end - start - 3;
changeAllTpcs(notes[end - 3], tab[(notes[end - 3]->pitch() % 12) * 2 + ((opt & (1 << k)) >> k)]);
- // FALLTHROUGH
+ [[fallthrough]];
case 2:
k = end - start - 2;
changeAllTpcs(notes[end - 2], tab[(notes[end - 2]->pitch() % 12) * 2 + ((opt & (1 << k)) >> k)]);
- // FALLTHROUGH
+ [[fallthrough]];
case 1:
k = end - start - 1;
changeAllTpcs(notes[end - 1], tab[(notes[end - 1]->pitch() % 12) * 2 + ((opt & (1 << k)) >> k)]);
diff --git a/src/engraving/dom/property.cpp b/src/engraving/dom/property.cpp
index 6c3ee312a59c4..db00184e1fb20 100644
--- a/src/engraving/dom/property.cpp
+++ b/src/engraving/dom/property.cpp
@@ -147,8 +147,7 @@ static constexpr PropertyMetaData propertyList[] = {
{ Pid::FRET_FRAME_ROW_GAP, false, "fretFrameRowGap", P_TYPE::SPATIUM, PropertyGroup::APPEARANCE, DUMMY_QT_TR_NOOP("propertyName", "row gap") },
{ Pid::FRET_FRAME_CHORDS_PER_ROW, false, "fretFrameChordsPerRow", P_TYPE::INT, PropertyGroup::APPEARANCE, DUMMY_QT_TR_NOOP("propertyName", "chords per row") },
{ Pid::FRET_FRAME_H_ALIGN, false, "fretFrameHorizontalAlign", P_TYPE::INT, PropertyGroup::APPEARANCE, DUMMY_QT_TR_NOOP("propertyName", "horizontal alignment") },
- { Pid::FRET_FRAME_DIAGRAMS_ORDER, false, "fretFrameDiagramsOrder", P_TYPE::STRING, PropertyGroup::APPEARANCE, DUMMY_QT_TR_NOOP("propertyName", "diagrams order") },
- { Pid::FRET_FRAME_INVISIBLE_DIAGRAMS, false, "fretFrameInvisibleDiagrams", P_TYPE::STRING, PropertyGroup::APPEARANCE, DUMMY_QT_TR_NOOP("propertyName", "invisible diagrams") },
+ { Pid::FRET_FRAME_DIAGRAMS_ORDER, false, "fretFrameDiagramsOrder", P_TYPE::STRING, PropertyGroup::NONE, DUMMY_QT_TR_NOOP("propertyName", "diagrams order") },
{ Pid::SCALE, false, "scale", P_TYPE::SCALE, PropertyGroup::APPEARANCE, DUMMY_QT_TR_NOOP("propertyName", "scale") },
{ Pid::LOCK_ASPECT_RATIO, false, "lockAspectRatio", P_TYPE::BOOL, PropertyGroup::APPEARANCE, DUMMY_QT_TR_NOOP("propertyName", "aspect ratio locked") },
diff --git a/src/engraving/dom/property.h b/src/engraving/dom/property.h
index 4a33f3bba0350..2d238d3303231 100644
--- a/src/engraving/dom/property.h
+++ b/src/engraving/dom/property.h
@@ -155,7 +155,6 @@ enum class Pid {
FRET_FRAME_CHORDS_PER_ROW,
FRET_FRAME_H_ALIGN,
FRET_FRAME_DIAGRAMS_ORDER,
- FRET_FRAME_INVISIBLE_DIAGRAMS,
SCALE,
LOCK_ASPECT_RATIO,
diff --git a/src/engraving/dom/realizedharmony.cpp b/src/engraving/dom/realizedharmony.cpp
index bdf734b67ac07..3e5a66e9e1d29 100644
--- a/src/engraving/dom/realizedharmony.cpp
+++ b/src/engraving/dom/realizedharmony.cpp
@@ -124,7 +124,7 @@ const RealizedHarmony::PitchMap RealizedHarmony::generateNotes(int rootTpc, int
if (!m_harmony->parsedForm()->understandable()) {
break;
}
- // FALLTHROUGH
+ [[fallthrough]];
case Voicing::CLOSE: //Voices notes in close position in the first octave above middle C
{
notes.insert({ rootPitch + DEFAULT_OCTAVE * PITCH_DELTA_OCTAVE, rootTpc });
@@ -439,7 +439,7 @@ RealizedHarmony::PitchMap RealizedHarmony::getIntervals(int rootTpc, bool litera
ret.insert({ 9 + RANK_MULT * RANK_ADD, tpcInterval(rootTpc, 13, 0) }); //maj13
omit |= 1 << 13;
}
- // FALLTHROUGH
+ [[fallthrough]];
case 11:
if (!(omit & (1 << 11))) {
if (quality == "minor") {
@@ -449,13 +449,13 @@ RealizedHarmony::PitchMap RealizedHarmony::getIntervals(int rootTpc, bool litera
}
omit |= 1 << 11;
}
- // FALLTHROUGH
+ [[fallthrough]];
case 9:
if (!(omit & (1 << 9))) {
ret.insert({ 2 + RANK_MULT * RANK_9TH, tpcInterval(rootTpc, 9, 0) }); //maj9
omit |= 1 << 9;
}
- // FALLTHROUGH
+ [[fallthrough]];
case 7:
if (!(omit & (1 << 7))) {
if (quality == "major") {
diff --git a/src/engraving/dom/spanner.cpp b/src/engraving/dom/spanner.cpp
index ce0be57a65def..3f469acdcb5aa 100644
--- a/src/engraving/dom/spanner.cpp
+++ b/src/engraving/dom/spanner.cpp
@@ -1621,12 +1621,18 @@ String SpannerSegment::formatBarsAndBeats() const
endSegment = score()->lastSegment()->prev1MM(SegmentType::ChordRest);
}
- if (endSegment->tick() != score()->lastSegment()->prev1MM(SegmentType::ChordRest)->tick()
+ if (endSegment->tick() > Fraction(0, 1)
+ && endSegment->tick() != score()->lastSegment()->prev1MM(SegmentType::ChordRest)->tick()
&& spanner->type() != ElementType::SLUR
+ && spanner->type() != ElementType::HAMMER_ON_PULL_OFF
&& spanner->type() != ElementType::TIE) {
endSegment = endSegment->prev1MM(SegmentType::ChordRest);
}
+ IF_ASSERT_FAILED(endSegment) {
+ return EngravingItem::formatBarsAndBeats();
+ }
+
return formatStartBarsAndBeats(spanner->startSegment()) + u' ' + formatEndBarsAndBeats(endSegment);
}
diff --git a/src/engraving/dom/staff.cpp b/src/engraving/dom/staff.cpp
index 0fb94e6a092ec..059d48a6f58e0 100644
--- a/src/engraving/dom/staff.cpp
+++ b/src/engraving/dom/staff.cpp
@@ -249,6 +249,11 @@ bool Staff::shouldShowMeasureNumbers() const
return false;
}
+bool Staff::isLastOfScore() const
+{
+ return score()->staves().empty() ? false : score()->staves().back() == this;
+}
+
bool Staff::isSystemObjectStaff() const
{
return score() && muse::contains(score()->systemObjectStaves(), const_cast(this));
@@ -256,7 +261,7 @@ bool Staff::isSystemObjectStaff() const
bool Staff::hasSystemObjectsBelowBottomStaff() const
{
- return isSystemObjectStaff() && score()->staves().back() == this && style().styleB(Sid::systemObjectsBelowBottomStaff);
+ return isSystemObjectStaff() && isLastOfScore() && style().styleB(Sid::systemObjectsBelowBottomStaff);
}
//---------------------------------------------------------
diff --git a/src/engraving/dom/staff.h b/src/engraving/dom/staff.h
index 3cbae73a04382..f884c745e082a 100644
--- a/src/engraving/dom/staff.h
+++ b/src/engraving/dom/staff.h
@@ -264,6 +264,7 @@ class Staff final : public EngravingItem
void undoSetShowMeasureNumbers(bool show);
bool shouldShowMeasureNumbers() const;
+ bool isLastOfScore() const;
bool isSystemObjectStaff() const;
bool hasSystemObjectsBelowBottomStaff() const;
diff --git a/src/engraving/rendering/score/harmonylayout.cpp b/src/engraving/rendering/score/harmonylayout.cpp
index 3872820cfcafa..1c4add953bc13 100644
--- a/src/engraving/rendering/score/harmonylayout.cpp
+++ b/src/engraving/rendering/score/harmonylayout.cpp
@@ -500,7 +500,7 @@ void HarmonyLayout::renderSingleHarmony(Harmony* item, Harmony::LayoutData* ldat
// render bass
if (tpcIsValid(info->bassTpc())) {
- std::list& bassNoteChordList
+ std::list bassNoteChordList
= style.styleB(Sid::chordBassNoteStagger) ? chordList->renderListBassOffset : chordList->renderListBass;
static const std::wregex PATTERN_69 = std::wregex(L"6[,/]?9");
diff --git a/src/engraving/rendering/score/horizontalspacing.cpp b/src/engraving/rendering/score/horizontalspacing.cpp
index c25536877f934..b926a5b62c46b 100644
--- a/src/engraving/rendering/score/horizontalspacing.cpp
+++ b/src/engraving/rendering/score/horizontalspacing.cpp
@@ -309,7 +309,7 @@ std::vector HorizontalSpacing::spaceSegments
}
if (ctx.systemIsFull) {
- checkLyricsAgainstRightMargin(placedSegments);
+ checkLyricsAgainstRightMargin(placedSegments, ctx);
checkLargeTimeSigAgainstRightMargin(placedSegments);
}
@@ -473,13 +473,20 @@ void HorizontalSpacing::checkLyricsAgainstLeftMargin(Segment* segment, double& x
}
}
-void HorizontalSpacing::checkLyricsAgainstRightMargin(std::vector& segPositions)
+void HorizontalSpacing::checkLyricsAgainstRightMargin(std::vector& segPositions, const HorizontalSpacingContext& ctx)
{
+ const double systemEdge = segPositions.back().xPosInSystemCoords + segPositions.back().segment->minRight();
+ const MStyle& style = ctx.system->style();
+ const bool lyricsDashForce = style.styleB(Sid::lyricsDashForce);
+ const bool lyricsMelismaForce = style.styleB(Sid::lyricsMelismaForce);
+ const double minSpaceForDash = lyricsDashForce ? style.styleMM(Sid::lyricsDashPad) + style.styleMM(Sid::lyricsDashMinLength)
+ + style.styleMM(Sid::lineEndToBarlineDistance) + segPositions.back().segment->minRight() : 0.0;
+ const double minSpaceForMelisma = lyricsMelismaForce ? style.styleMM(Sid::lyricsMelismaPad) + style.styleMM(Sid::lyricsMelismaMinLength)
+ + style.styleMM(Sid::lineEndToBarlineDistance) + segPositions.back().segment->minRight() : 0.0;
+
int chordRestSegmentsCount = 0;
for (size_t i = segPositions.size(); i > 1; --i) {
- double systemEdge = segPositions.back().xPosInSystemCoords + segPositions.back().segment->minRight();
-
SegmentPosition& segPos = segPositions[i - 1];
double x = segPos.xPosInSystemCoords;
Segment* seg = segPos.segment;
@@ -495,7 +502,16 @@ void HorizontalSpacing::checkLyricsAgainstRightMargin(std::vectorshapes()) {
for (const ShapeElement& shapeEl : shape.elements()) {
if (shapeEl.item() && shapeEl.item()->isLyrics()) {
- xMaxLyrics = std::max(xMaxLyrics, x + shapeEl.right());
+ const Lyrics* lyrics = toLyrics(shapeEl.item());
+ bool hasMelisma = lyrics->separator() && lyrics->separator()->isEndMelisma();
+ bool hasDash = lyrics->syllabic() == LyricsSyllabic::BEGIN || lyrics->syllabic() == LyricsSyllabic::MIDDLE;
+ double rightEdge = x + shapeEl.right();
+ if (hasDash) {
+ rightEdge += minSpaceForDash;
+ } else if (hasMelisma) {
+ rightEdge += minSpaceForMelisma;
+ }
+ xMaxLyrics = std::max(xMaxLyrics, rightEdge);
}
}
}
diff --git a/src/engraving/rendering/score/horizontalspacing.h b/src/engraving/rendering/score/horizontalspacing.h
index b556a57206b65..14a7a4222ec00 100644
--- a/src/engraving/rendering/score/horizontalspacing.h
+++ b/src/engraving/rendering/score/horizontalspacing.h
@@ -112,7 +112,7 @@ class HorizontalSpacing
HorizontalSpacingContext& ctx);
static bool stopCheckingPreviousSegments(const SegmentPosition& prev, const SegmentPosition& curSegPos);
static void checkLyricsAgainstLeftMargin(Segment* segment, double& x, HorizontalSpacingContext& ctx);
- static void checkLyricsAgainstRightMargin(std::vector& segPositions);
+ static void checkLyricsAgainstRightMargin(std::vector& segPositions, const HorizontalSpacingContext& ctx);
static double spaceLyricsAgainstBarlines(Segment* firstSeg, Segment* secondSeg, const HorizontalSpacingContext& ctx);
static void checkLargeTimeSigAgainstRightMargin(std::vector& segPositions);
static void moveRightAlignedSegments(std::vector& placedSegments, const HorizontalSpacingContext& ctx);
diff --git a/src/engraving/rendering/score/restlayout.cpp b/src/engraving/rendering/score/restlayout.cpp
index 33f4e7ab3c9be..94e4933d48d72 100644
--- a/src/engraving/rendering/score/restlayout.cpp
+++ b/src/engraving/rendering/score/restlayout.cpp
@@ -602,7 +602,7 @@ void RestLayout::checkFullMeasureRestCollisions(const System* system, LayoutCont
}
measureShape.remove_if([fullMeasureRest] (const ShapeElement& shapeEl) {
const EngravingItem* shapeItem = shapeEl.item();
- return shapeItem && (shapeItem == fullMeasureRest || shapeItem->isBarLine());
+ return shapeItem && (shapeItem == fullMeasureRest || shapeItem->isBarLine() || shapeItem->isAccidental());
});
const double spatium = fullMeasureRest->spatium();
diff --git a/src/engraving/rendering/score/tlayout.cpp b/src/engraving/rendering/score/tlayout.cpp
index 656e54db09b2a..9a159e3b75078 100644
--- a/src/engraving/rendering/score/tlayout.cpp
+++ b/src/engraving/rendering/score/tlayout.cpp
@@ -1497,17 +1497,14 @@ void TLayout::layoutFBox(const FBox* item, FBox::LayoutData* ldata, const Layout
ldata->setPos(PointF());
- const ElementList& elements = item->orderedElements(true /*includeInvisible*/);
- const StringList& invisibleDiagrams = item->invisibleDiagrams();
-
std::vector fretDiagrams;
- for (EngravingItem* element : elements) {
+ for (EngravingItem* element : item->el()) {
if (!element || !element->isFretDiagram() || !element->visible()) {
continue;
}
FretDiagram* diagram = toFretDiagram(element);
- if (muse::contains(invisibleDiagrams, diagram->harmony()->harmonyName().toLower())) {
+ if (!diagram->visible()) {
//! NOTE: We need to layout the diagrams to get the harmony names to show in the UI
layoutItem(diagram, const_cast(ctx));
@@ -2823,8 +2820,8 @@ void TLayout::layoutFretDiagram(const FretDiagram* item, FretDiagram::LayoutData
int endString = barre.endString != -1 ? barre.endString : item->strings() - 1;
int fret = i.first;
bool slurStyleBarre = ctx.conf().styleB(Sid::barreAppearanceSlur);
- for (int string = 0; string < item->strings(); ++string) {
- if (slurStyleBarre && string >= startString && string <= endString) {
+ for (int string = startString; string <= endString; ++string) {
+ if (slurStyleBarre) {
const_cast(item)->addDotForDotStyleBarre(string, fret);
} else {
const_cast(item)->removeDotForDotStyleBarre(string, fret);
diff --git a/src/engraving/rw/read460/read460.cpp b/src/engraving/rw/read460/read460.cpp
index a2091417eb477..172283a3c4bba 100644
--- a/src/engraving/rw/read460/read460.cpp
+++ b/src/engraving/rw/read460/read460.cpp
@@ -617,7 +617,9 @@ bool Read460::pasteStaff(XmlReader& e, Segment* dst, staff_idx_t dstStaff, Fract
Fraction tick = doScale ? (ctx.tick() - dstTick) * scale + dstTick : ctx.tick();
Measure* m = score->tick2measure(tick);
- Segment* seg = m->undoGetChordRestOrTimeTickSegment(tick);
+ Segment* seg = el->isFretDiagram()
+ ? m->undoGetSegment(SegmentType::ChordRest, tick)
+ : m->undoGetChordRestOrTimeTickSegment(tick);
el->setParent(seg);
// be sure to paste the element in the destination track;
diff --git a/src/engraving/rw/read460/tread.cpp b/src/engraving/rw/read460/tread.cpp
index 0a0ae71b391c4..430a3b1dde837 100644
--- a/src/engraving/rw/read460/tread.cpp
+++ b/src/engraving/rw/read460/tread.cpp
@@ -2113,8 +2113,6 @@ void TRead::read(FBox* b, XmlReader& xml, ReadContext& ctx)
} else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_ROW_GAP)) {
} else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_CHORDS_PER_ROW)) {
} else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_H_ALIGN)) {
- } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_DIAGRAMS_ORDER)) {
- } else if (readProperty(b, tag, xml, ctx, Pid::FRET_FRAME_INVISIBLE_DIAGRAMS)) {
} else if (TRead::readProperties(static_cast(b), xml, ctx)) {
} else {
xml.unknown();
@@ -4346,9 +4344,6 @@ bool TRead::readProperties(TextBase* t, XmlReader& e, ReadContext& ctx)
{
const AsciiStringView tag(e.name());
for (Pid i : TextBasePropertyId) {
- if (i == Pid::POSITION && tag == propertyName(i)) {
- LOGI() << "read pos";
- }
if (TRead::readProperty(t, tag, e, ctx, i)) {
return true;
}
diff --git a/src/engraving/rw/write/twrite.cpp b/src/engraving/rw/write/twrite.cpp
index 299af42c6b25c..71373eb2291c8 100644
--- a/src/engraving/rw/write/twrite.cpp
+++ b/src/engraving/rw/write/twrite.cpp
@@ -822,8 +822,6 @@ void TWrite::write(const FBox* item, XmlWriter& xml, WriteContext& ctx)
writeProperty(item, xml, Pid::FRET_FRAME_ROW_GAP);
writeProperty(item, xml, Pid::FRET_FRAME_CHORDS_PER_ROW);
writeProperty(item, xml, Pid::FRET_FRAME_H_ALIGN);
- writeProperty(item, xml, Pid::FRET_FRAME_DIAGRAMS_ORDER);
- writeProperty(item, xml, Pid::FRET_FRAME_INVISIBLE_DIAGRAMS);
writeProperties(static_cast(item), xml, ctx);
diff --git a/src/engraving/tests/fretbox_tests.cpp b/src/engraving/tests/fretbox_tests.cpp
index 13a097fe28b1e..245f7efa1763d 100644
--- a/src/engraving/tests/fretbox_tests.cpp
+++ b/src/engraving/tests/fretbox_tests.cpp
@@ -161,7 +161,12 @@ class Engraving_FretBoxTests : public ::testing::Test
FBox* fretBox = toFBox(score->measure(0));
ASSERT_TRUE(fretBox);
- const ElementList& elements = fretBox->orderedElements(false /*includeInvisible*/);
+ ElementList elements;
+ for (EngravingItem* item : fretBox->el()) {
+ if (item->visible()) {
+ elements.push_back(item);
+ }
+ }
EXPECT_EQ(elements.size(), chords.size());
for (size_t i = 0; i < chords.size(); ++i) {
diff --git a/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp b/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp
index 2ea2574cd8b51..e7a49f71e7fc5 100644
--- a/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp
+++ b/src/inspector/models/notation/frames/fretframe/fretframechordlistmodel.cpp
@@ -57,15 +57,13 @@ void FretFrameChordListModel::load()
return name;
};
- const StringList& invisibleDiagrams = m_fretBox->invisibleDiagrams();
-
- for (EngravingItem* element : m_fretBox->orderedElements(true /*includeInvisible*/)) {
+ for (EngravingItem* element : m_fretBox->el()) {
FretDiagram* diagram = toFretDiagram(element);
auto chordItem = new FretFrameChordItem(this);
chordItem->setTitle(harmonyName(diagram->harmony()));
chordItem->setPlainText(diagram->harmonyText());
- chordItem->setIsVisible(!muse::contains(invisibleDiagrams, diagram->harmony()->harmonyName().toLower()));
+ chordItem->setIsVisible(diagram->visible());
items << chordItem;
}
@@ -107,7 +105,7 @@ void FretFrameChordListModel::setChordVisible(int index, bool visible)
return;
}
- ElementList diagrams = m_fretBox->orderedElements(true /*includeInvisible*/);
+ ElementList diagrams = m_fretBox->el();
if (index < 0 || index >= static_cast(diagrams.size())) {
return;
}
@@ -124,16 +122,8 @@ void FretFrameChordListModel::setChordVisible(int index, bool visible)
notation->undoStack()->prepareChanges(actionName);
FretDiagram* diagram = toFretDiagram(diagrams[index]);
- String harmonyName = diagram->harmony()->harmonyName().toLower();
-
- StringList invisibleDiagrams = m_fretBox->invisibleDiagrams();
- if (visible) {
- invisibleDiagrams.erase(std::remove(invisibleDiagrams.begin(), invisibleDiagrams.end(), harmonyName));
- } else {
- invisibleDiagrams.push_back(harmonyName);
- }
- m_fretBox->undoSetInvisibleDiagrams(invisibleDiagrams);
+ diagram->undoChangeProperty(Pid::VISIBLE, visible);
FretFrameChordItem* item = modelIndexToItem(this->index(index));
item->setIsVisible(visible);
diff --git a/src/inspector/models/parts/partssettingsmodel.cpp b/src/inspector/models/parts/partssettingsmodel.cpp
index 240bb5159386f..5f7a7d3c8f641 100644
--- a/src/inspector/models/parts/partssettingsmodel.cpp
+++ b/src/inspector/models/parts/partssettingsmodel.cpp
@@ -65,7 +65,7 @@ void PartsSettingsModel::requestElements()
m_elementsForTextLinkingOption.clear();
for (EngravingItem* item : m_elementList) {
- if (!item->score()->isMaster() && !item->isLayoutBreak()) {
+ if (!item->score()->isMaster() && !item->isLayoutBreak() && !item->isFBox()) {
m_elementsForPartLinkingOption.push_back(item);
}
if (item->canBeExcludedFromOtherParts()) {
@@ -101,6 +101,13 @@ void PartsSettingsModel::onNotationChanged(const PropertyIdSet&, const StyleIdSe
loadProperties();
}
+void PartsSettingsModel::onCurrentNotationChanged()
+{
+ emit isMasterScoreChanged(isMasterNotation());
+
+ AbstractInspectorModel::onCurrentNotationChanged();
+}
+
PropertyItem* PartsSettingsModel::positionLinkedToMaster() const
{
return m_positionLinkedToMaster;
@@ -136,6 +143,11 @@ bool PartsSettingsModel::showTextLinkingOption() const
return m_showTextLinkingOption;
}
+bool PartsSettingsModel::isMasterScore() const
+{
+ return isMasterNotation();
+}
+
void PartsSettingsModel::updateShowPartLinkingOption()
{
bool showPartLinking = !m_elementsForPartLinkingOption.empty();
diff --git a/src/inspector/models/parts/partssettingsmodel.h b/src/inspector/models/parts/partssettingsmodel.h
index 4026c4dee7592..c853ac777675c 100644
--- a/src/inspector/models/parts/partssettingsmodel.h
+++ b/src/inspector/models/parts/partssettingsmodel.h
@@ -36,6 +36,7 @@ class PartsSettingsModel : public AbstractInspectorModel
Q_PROPERTY(bool showPartLinkingOption READ showPartLinkingOption NOTIFY showPartLinkingOptionChanged)
Q_PROPERTY(bool showExcludeOption READ showExcludeOption NOTIFY showExcludeOptionChanged)
Q_PROPERTY(bool showTextLinkingOption READ showTextLinkingOption NOTIFY showTextLinkingOptionChanged)
+ Q_PROPERTY(bool isMasterScore READ isMasterScore NOTIFY isMasterScoreChanged)
public:
explicit PartsSettingsModel(QObject* parent, IElementRepositoryService* repository);
@@ -48,11 +49,13 @@ class PartsSettingsModel : public AbstractInspectorModel
bool showPartLinkingOption() const;
bool showExcludeOption() const;
bool showTextLinkingOption() const;
+ bool isMasterScore() const;
signals:
void showPartLinkingOptionChanged(bool showPartsOption);
void showExcludeOptionChanged(bool excludeOption);
void showTextLinkingOptionChanged(bool showTextLink);
+ void isMasterScoreChanged(bool isMasterScore);
private:
void createProperties() override;
@@ -60,6 +63,7 @@ class PartsSettingsModel : public AbstractInspectorModel
void loadProperties() override;
void resetProperties() override;
void onNotationChanged(const mu::engraving::PropertyIdSet&, const mu::engraving::StyleIdSet&) override;
+ void onCurrentNotationChanged() override;
void updateShowPartLinkingOption();
void updateShowExcludeOption();
diff --git a/src/inspector/view/qml/MuseScore/Inspector/parts/PartsSettings.qml b/src/inspector/view/qml/MuseScore/Inspector/parts/PartsSettings.qml
index 45bbe4a7f5a21..6bd8b0a27ca08 100644
--- a/src/inspector/view/qml/MuseScore/Inspector/parts/PartsSettings.qml
+++ b/src/inspector/view/qml/MuseScore/Inspector/parts/PartsSettings.qml
@@ -106,9 +106,9 @@ InspectorSectionView {
navigation.panel: root.navigationPanel
navigation.row: root.navigationRowStart
- text: root.model && root.model.showPartLinkingOption
- ? qsTrc("inspector", "Exclude from score")
- : qsTrc("inspector", "Exclude from parts")
+ text: root.model && root.model.isMasterScore
+ ? qsTrc("inspector", "Exclude from parts")
+ : qsTrc("inspector", "Exclude from score")
}
}
}
diff --git a/src/instrumentsscene/view/roottreeitem.cpp b/src/instrumentsscene/view/roottreeitem.cpp
index 6c0454f415852..f36d048dc952c 100644
--- a/src/instrumentsscene/view/roottreeitem.cpp
+++ b/src/instrumentsscene/view/roottreeitem.cpp
@@ -218,7 +218,7 @@ MoveParams RootTreeItem::buildSystemObjectsMoveParams(int sourceRow, int count,
if ((sourceIsSystemObjectLayer && moveUp) || (sourceIsPartLayer && moveDown)) {
moveParams.moveSysObjAboveBottomStaff = true;
}
- } else if (sourceIsPartLayer && moveUp) {
+ } else if (sourceIsPartLayer && srcStaff->isLastOfScore() && moveUp) {
moveParams.moveSysObjBelowBottomStaff = true;
}
diff --git a/src/notation/inotationparts.h b/src/notation/inotationparts.h
index e1f2ca62439c9..33305404bbe03 100644
--- a/src/notation/inotationparts.h
+++ b/src/notation/inotationparts.h
@@ -72,6 +72,7 @@ class INotationParts
InsertMode mode = InsertMode::Before) = 0;
virtual bool appendStaff(Staff* staff, const muse::ID& destinationPartId) = 0;
+ virtual bool appendStaffLinkedToMaster(Staff* staff, Staff* masterSourceStaff, const muse::ID& destinationPartId) = 0;
virtual bool appendLinkedStaff(Staff* staff, const muse::ID& sourceStaffId, const muse::ID& destinationPartId) = 0;
virtual void insertPart(Part* part, size_t index) = 0;
diff --git a/src/notation/internal/masternotationparts.cpp b/src/notation/internal/masternotationparts.cpp
index c8313a9954b85..2839f29c4dded 100644
--- a/src/notation/internal/masternotationparts.cpp
+++ b/src/notation/internal/masternotationparts.cpp
@@ -145,9 +145,8 @@ bool MasterNotationParts::appendStaff(Staff* staff, const ID& destinationPartId)
for (const INotationPartsPtr& parts : excerptsParts()) {
Staff* excerptStaff = staff->clone();
- if (parts->appendStaff(excerptStaff, destinationPartId)) {
- excerptStaff->linkTo(staff);
- } else {
+ if (!parts->appendStaffLinkedToMaster(excerptStaff, staff, destinationPartId)) {
+ excerptStaff->undoUnlink();
delete excerptStaff;
}
}
diff --git a/src/notation/internal/masternotationparts.h b/src/notation/internal/masternotationparts.h
index bdf080d5d2cf4..f0eec2953bc11 100644
--- a/src/notation/internal/masternotationparts.h
+++ b/src/notation/internal/masternotationparts.h
@@ -40,6 +40,7 @@ class MasterNotationParts : public NotationParts
void removeStaves(const muse::IDList& stavesIds) override;
bool appendStaff(Staff* staff, const muse::ID& destinationPartId) override;
+ bool appendStaffLinkedToMaster(Staff*, Staff*, const muse::ID&) override { return false; }
bool appendLinkedStaff(Staff* staff, const muse::ID& sourceStaffId, const muse::ID& destinationPartId) override;
void replaceInstrument(const InstrumentKey& instrumentKey, const Instrument& newInstrument,
diff --git a/src/notation/internal/notationinteraction.cpp b/src/notation/internal/notationinteraction.cpp
index 770dfe3d0b916..403f65236dd37 100644
--- a/src/notation/internal/notationinteraction.cpp
+++ b/src/notation/internal/notationinteraction.cpp
@@ -5089,6 +5089,7 @@ void NotationInteraction::addBoxes(BoxType boxType, int count, int beforeBoxInde
options.createEmptyMeasures = false;
options.moveSignaturesClef = moveSignaturesClef;
options.needDeselectAll = false;
+ options.cloneBoxToAllParts = boxType != BoxType::Fret;
for (int i = 0; i < count; ++i) {
score()->insertMeasure(elementType, beforeBox, options);
diff --git a/src/notation/internal/notationparts.cpp b/src/notation/internal/notationparts.cpp
index 64b55f9060711..7cd0c8968054a 100644
--- a/src/notation/internal/notationparts.cpp
+++ b/src/notation/internal/notationparts.cpp
@@ -600,6 +600,29 @@ bool NotationParts::appendStaff(Staff* staff, const ID& destinationPartId)
return true;
}
+bool NotationParts::appendStaffLinkedToMaster(Staff* staff, Staff* masterSourceStaff, const muse::ID& destinationPartId)
+{
+ TRACEFUNC;
+
+ IF_ASSERT_FAILED(staff && masterSourceStaff) {
+ return false;
+ }
+
+ Part* destinationPart = partModifiable(destinationPartId);
+ if (!destinationPart) {
+ return false;
+ }
+
+ startEdit(TranslatableString("undoableAction", "Add staff"));
+
+ doAppendStaff(staff, destinationPart, /*createRests*/ false);
+ score()->undo(new mu::engraving::Link(staff, masterSourceStaff));
+
+ mu::engraving::Excerpt::cloneStaff2(masterSourceStaff, staff, Fraction(0, 1), score()->endTick());
+
+ return true;
+}
+
bool NotationParts::appendLinkedStaff(Staff* staff, const muse::ID& sourceStaffId, const muse::ID& destinationPartId)
{
TRACEFUNC;
diff --git a/src/notation/internal/notationparts.h b/src/notation/internal/notationparts.h
index 34e244cae241f..2a704c486e784 100644
--- a/src/notation/internal/notationparts.h
+++ b/src/notation/internal/notationparts.h
@@ -66,6 +66,7 @@ class NotationParts : public INotationParts, public muse::async::Asyncable
void moveStaves(const muse::IDList& sourceStavesIds, const muse::ID& destinationStaffId, InsertMode mode = InsertMode::Before) override;
bool appendStaff(Staff* staff, const muse::ID& destinationPartId) override;
+ bool appendStaffLinkedToMaster(Staff* staff, Staff* masterSourceStaff, const muse::ID& destinationPartId) override;
bool appendLinkedStaff(Staff* staff, const muse::ID& sourceStaffId, const muse::ID& destinationPartId) override;
void insertPart(Part* part, size_t index) override;
diff --git a/vtest/scores/lyrics-30.mscz b/vtest/scores/lyrics-30.mscz
new file mode 100644
index 0000000000000..cd936b1795173
Binary files /dev/null and b/vtest/scores/lyrics-30.mscz differ