Skip to content

Commit 72829c1

Browse files
committed
Add support for spanners
1 parent 18abaea commit 72829c1

2 files changed

Lines changed: 131 additions & 1 deletion

File tree

src/engraving/rendering/score/stavesharinglayout.cpp

Lines changed: 126 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,10 @@ bool StaveSharingLayout::isUnison(track_idx_t prevTrack, track_idx_t nextTrack,
269269
}
270270
}
271271

272+
if (!checkSpannersForSameVoice(prevTrack, nextTrack, ctx)) {
273+
return false;
274+
}
275+
272276
return true;
273277
}
274278

@@ -352,6 +356,10 @@ bool StaveSharingLayout::canGoToSameVoice(track_idx_t prevTrack, track_idx_t nex
352356
}
353357
}
354358

359+
if (!checkSpannersForSameVoice(prevTrack, nextTrack, ctx)) {
360+
return false;
361+
}
362+
355363
for (Note* unisonNote : potentialUnisonNotes) {
356364
localUnisonNotes.insert(unisonNote);
357365
}
@@ -463,6 +471,47 @@ bool StaveSharingLayout::checkNoteSpannersForUnison(const Note* note1, const Not
463471
return true;
464472
}
465473

474+
bool StaveSharingLayout::checkSpannersForSameVoice(track_idx_t prevTrack, track_idx_t nextTrack, StaveSharingContext& ctx)
475+
{
476+
std::multimap<ElementType, Spanner*> spannersOnPrevTrack;
477+
std::multimap<ElementType, Spanner*> spannersOnNextTrack;
478+
479+
for (Spanner* spanner : ctx.overlappingSpanners) {
480+
if (spanner->track() == prevTrack) {
481+
spannersOnPrevTrack.insert({ spanner->type(), spanner });
482+
} else if (spanner->track() == nextTrack) {
483+
spannersOnNextTrack.insert({ spanner->type(), spanner });
484+
}
485+
}
486+
487+
if (spannersOnPrevTrack.size() != spannersOnNextTrack.size()) {
488+
return false;
489+
}
490+
491+
for (auto [type, spanner] : spannersOnPrevTrack) {
492+
auto range = spannersOnNextTrack.equal_range(type);
493+
if (range.first == range.second) {
494+
// No spanner of this type exists in nextTrack
495+
return false;
496+
}
497+
498+
Spanner* matchingSpanner = nullptr;
499+
for (auto i = range.first; i != range.second; ++i) {
500+
Spanner* nextSpanner = i->second;
501+
if (nextSpanner->tick() == spanner->tick() && nextSpanner->ticks() == spanner->ticks()) {
502+
matchingSpanner = nextSpanner;
503+
break;
504+
}
505+
}
506+
507+
if (!matchingSpanner) {
508+
return false;
509+
}
510+
}
511+
512+
return true;
513+
}
514+
466515
bool StaveSharingLayout::canGoToSameStave(track_idx_t prevTrack, track_idx_t nextTrack,
467516
StaveSharingContext& ctx)
468517
{
@@ -580,12 +629,19 @@ void StaveSharingLayout::disconnectAll(SharedPart* p, StaveSharingContext& ctx)
580629
}
581630
}
582631
}
632+
633+
for (Spanner* spanner : ctx.overlappingSpanners) {
634+
if (!spanner->systemFlag() && spanner->track() >= startTrack && spanner->track() < endTrack) {
635+
EngravingItem::disconnectAllOriginItems(spanner);
636+
}
637+
}
583638
}
584639

585640
void StaveSharingLayout::makeSharedNotation(SharedPart* p, StaveSharingContext& ctx)
586641
{
587642
makeSharedChordRests(p, ctx);
588643
makeSharedAnnotations(p, ctx);
644+
makeSharedSpanners(p, ctx);
589645
}
590646

591647
void StaveSharingLayout::makeSharedChordRests(SharedPart* p, StaveSharingContext& ctx)
@@ -818,7 +874,65 @@ void StaveSharingLayout::makeSharedAnnotations(SharedPart* p, StaveSharingContex
818874
}
819875
}
820876

821-
for (EngravingItem* sharedItem : sharedAnnotations) {
877+
manageVoicePropertyAndTrackForSharedItems(sharedAnnotations, startOriginTrack, endOriginTrack, trackMap);
878+
}
879+
880+
void StaveSharingLayout::makeSharedSpanners(SharedPart* p, StaveSharingContext& ctx)
881+
{
882+
const SharedTrackMap& trackMap = p->trackMapAtTick(ctx.sTick);
883+
track_idx_t startOriginTrack = trackMap.begin()->first;
884+
track_idx_t endOriginTrack = trackMap.rbegin()->first;
885+
886+
std::vector<EngravingItem*> sharedSpanners;
887+
888+
std::vector<Spanner*> overlappingSpanners = ctx.overlappingSpanners; // copy because we may add
889+
for (Spanner* spanner : overlappingSpanners) {
890+
if (spanner->track() < startOriginTrack || spanner->track() > endOriginTrack) {
891+
continue;
892+
}
893+
894+
track_idx_t originTrack = spanner->track();
895+
IF_ASSERT_FAILED(muse::contains(trackMap, originTrack)) {
896+
continue;
897+
}
898+
899+
track_idx_t sharedTrack = trackMap.at(originTrack);
900+
901+
Spanner* sharedSpanner = nullptr;
902+
for (Spanner* possibleSharedSpanner : ctx.overlappingSpanners) {
903+
if (possibleSharedSpanner->track() == sharedTrack && possibleSharedSpanner->type() == spanner->type()
904+
&& possibleSharedSpanner->tick() == spanner->tick() && possibleSharedSpanner->ticks() == spanner->ticks()) {
905+
sharedSpanner = possibleSharedSpanner;
906+
break;
907+
}
908+
}
909+
910+
if (!sharedSpanner) {
911+
sharedSpanner = toSpanner(spanner->clone());
912+
sharedSpanner->setTrack(sharedTrack);
913+
sharedSpanner->setTick(spanner->tick());
914+
sharedSpanner->setTicks(spanner->ticks());
915+
sharedSpanner->setStartElement(nullptr);
916+
sharedSpanner->setEndElement(nullptr);
917+
sharedSpanner->reset();
918+
919+
ctx.score->undoAddElement(sharedSpanner);
920+
ctx.overlappingSpanners.push_back(sharedSpanner);
921+
}
922+
923+
EngravingItem::connectSharedItem(sharedSpanner, spanner);
924+
925+
sharedSpanners.push_back(sharedSpanner);
926+
}
927+
928+
manageVoicePropertyAndTrackForSharedItems(sharedSpanners, startOriginTrack, endOriginTrack, trackMap);
929+
}
930+
931+
void StaveSharingLayout::manageVoicePropertyAndTrackForSharedItems(const std::vector<EngravingItem*>& sharedItems,
932+
track_idx_t startOriginTrack, track_idx_t endOriginTrack,
933+
const SharedTrackMap& trackMap)
934+
{
935+
for (EngravingItem* sharedItem : sharedItems) {
822936
bool refersToVoice2 = track2voice(sharedItem->track()) != 0;
823937
bool voice2isUsed = refersToVoice2;
824938
if (!voice2isUsed) {
@@ -928,6 +1042,12 @@ void StaveSharingLayout::cleanup(SharedPart* p, StaveSharingContext& ctx)
9281042
}
9291043
}
9301044
}
1045+
1046+
for (Spanner* spanner : ctx.overlappingSpanners) {
1047+
if (!spanner->systemFlag() && spanner->track() >= startTrack && spanner->track() < endTrack && spanner->originItems().empty()) {
1048+
score->undoRemoveElement(spanner);
1049+
}
1050+
}
9311051
}
9321052

9331053
StaveSharingLayout::StaveSharingContext::StaveSharingContext(MeasureBase* first, MeasureBase* last, LayoutContext& ctx)
@@ -957,5 +1077,10 @@ StaveSharingLayout::StaveSharingContext::StaveSharingContext(MeasureBase* first,
9571077
sTick = crSegments.front()->tick();
9581078
eTick = crSegments.back()->measure()->endTick();
9591079
score = crSegments.front()->score();
1080+
1081+
auto spanners = score->spannerMap().findOverlapping(sTick.ticks(), eTick.ticks());
1082+
for (auto& i : spanners) {
1083+
overlappingSpanners.push_back(i.value);
1084+
}
9601085
}
9611086
}

src/engraving/rendering/score/stavesharinglayout.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ class StaveSharingLayout
4444
std::vector<Segment*> crSegments;
4545
std::vector<Segment*> segmentsToUpdate;
4646
std::vector<Segment*> crSegmentsToUpdate;
47+
std::vector<Spanner*> overlappingSpanners;
4748

4849
Score* score = nullptr;
4950
LayoutContext& layoutCtx;
@@ -64,6 +65,7 @@ class StaveSharingLayout
6465

6566
static bool checkAnnotationsForSameVoice(Segment* segment, track_idx_t prevTrack, track_idx_t nextTrack);
6667
static bool checkNoteSpannersForUnison(const Note* note1, const Note* note2);
68+
static bool checkSpannersForSameVoice(track_idx_t prevTrack, track_idx_t nextTrack, StaveSharingContext& ctx);
6769

6870
static bool canGoToSameStave(track_idx_t prevTrack, track_idx_t nextTrack, StaveSharingContext& ctx);
6971

@@ -75,6 +77,9 @@ class StaveSharingLayout
7577
static void makeSharedChordRests(SharedPart* p, StaveSharingContext& ctx);
7678
static void makeSharedTiesAndNoteSpanners(Note* originNote, Note* sharedNote);
7779
static void makeSharedAnnotations(SharedPart* p, StaveSharingContext& ctx);
80+
static void makeSharedSpanners(SharedPart* p, StaveSharingContext& ctx);
81+
static void manageVoicePropertyAndTrackForSharedItems(const std::vector<EngravingItem*>& sharedItems, track_idx_t startOriginTrack,
82+
track_idx_t endOriginTrack, const SharedTrackMap& trackMap);
7883

7984
static void cleanup(SharedPart* p, StaveSharingContext& ctx);
8085
};

0 commit comments

Comments
 (0)