From 77ae45aad19458159415c05c4180b11cdcb1170d Mon Sep 17 00:00:00 2001 From: James Date: Wed, 22 Nov 2023 09:14:21 +0000 Subject: [PATCH] Add figured bass to parts & score --- src/engraving/dom/edit.cpp | 6 ++- src/engraving/dom/engravingobject.h | 3 ++ src/engraving/dom/figuredbass.cpp | 82 ++++++++++++++++++++++++----- src/engraving/dom/figuredbass.h | 4 ++ src/engraving/types/types.h | 1 + src/engraving/types/typesconv.cpp | 1 + 6 files changed, 83 insertions(+), 14 deletions(-) diff --git a/src/engraving/dom/edit.cpp b/src/engraving/dom/edit.cpp index 5eec9280a9344..7275b1d1f49e3 100644 --- a/src/engraving/dom/edit.cpp +++ b/src/engraving/dom/edit.cpp @@ -5873,7 +5873,8 @@ void Score::undoAddElement(EngravingItem* element, bool addToLinkedStaves, bool && et != ElementType::FRET_DIAGRAM && et != ElementType::FERMATA && et != ElementType::HARMONY - && et != ElementType::HARP_DIAGRAM) + && et != ElementType::HARP_DIAGRAM + && et != ElementType::FIGURED_BASS) ) { undo(new AddElement(element)); return; @@ -6076,7 +6077,8 @@ void Score::undoAddElement(EngravingItem* element, bool addToLinkedStaves, bool || element->isFretDiagram() || element->isFermata() || element->isHarmony() - || element->isHarpPedalDiagram()) { + || element->isHarpPedalDiagram() + || element->isFiguredBass()) { Segment* segment = element->explicitParent()->isFretDiagram() ? toSegment(element->explicitParent()->explicitParent()) : toSegment( element->explicitParent()); diff --git a/src/engraving/dom/engravingobject.h b/src/engraving/dom/engravingobject.h index ea3a75eda5f12..ae77b4ccb6d08 100644 --- a/src/engraving/dom/engravingobject.h +++ b/src/engraving/dom/engravingobject.h @@ -78,6 +78,7 @@ class FBox; class FSymbol; class Fermata; class FiguredBass; +class FiguredBassItem; class Fingering; class FretDiagram; class Glissando; @@ -424,6 +425,7 @@ class EngravingObject CONVERT(LyricsLine, LYRICSLINE) CONVERT(LyricsLineSegment, LYRICSLINE_SEGMENT) CONVERT(FiguredBass, FIGURED_BASS) + CONVERT(FiguredBassItem, FIGURED_BASS_ITEM) CONVERT(StaffState, STAFF_STATE) CONVERT(Arpeggio, ARPEGGIO) CONVERT(Image, IMAGE) @@ -799,6 +801,7 @@ CONVERT(NoteHead) CONVERT(LyricsLine) CONVERT(LyricsLineSegment) CONVERT(FiguredBass) +CONVERT(FiguredBassItem) CONVERT(StaffState) CONVERT(Arpeggio) CONVERT(Image) diff --git a/src/engraving/dom/figuredbass.cpp b/src/engraving/dom/figuredbass.cpp index 6cda9e3924609..a685eeb365cd4 100644 --- a/src/engraving/dom/figuredbass.cpp +++ b/src/engraving/dom/figuredbass.cpp @@ -30,11 +30,13 @@ #include "chord.h" #include "factory.h" +#include "linkedobjects.h" #include "measure.h" #include "note.h" #include "rest.h" #include "score.h" #include "segment.h" +#include "undo.h" #include "log.h" @@ -78,7 +80,7 @@ const Char FiguredBassItem::NORM_PARENTH_TO_CHAR[int(FiguredBassItem::Parenthesi { 0, '(', ')', '[', ']' }; FiguredBassItem::FiguredBassItem(FiguredBass* parent, int l) - : EngravingItem(ElementType::INVALID, parent), m_ord(l) + : EngravingItem(ElementType::FIGURED_BASS_ITEM, parent), m_ord(l) { m_prefix = m_suffix = Modifier::NONE; m_digit = FBIDigitNone; @@ -706,8 +708,7 @@ Sid FiguredBass::getPropertyStyle(Pid id) const void FiguredBass::startEdit(EditData& ed) { - DeleteAll(m_items); - m_items.clear(); + clearItems(); renderer()->layoutText1(this); // re-layout without F.B.-specific formatting. TextBase::startEdit(ed); } @@ -737,24 +738,20 @@ void FiguredBass::endEdit(EditData& ed) // split text into lines and create an item for each line StringList list = txt.split(u'\n', mu::SkipEmptyParts); - DeleteAll(m_items); - m_items.clear(); + clearItems(); String normalizedText; int idx = 0; for (String str : list) { FiguredBassItem* pItem = new FiguredBassItem(this, idx++); if (!pItem->parse(str)) { // if any item fails parsing - DeleteAll(m_items); - m_items.clear(); // clear item list + clearItems(); score()->startCmd(); triggerLayout(); score()->endCmd(); delete pItem; return; } - pItem->setTrack(track()); - pItem->setParent(this); - m_items.push_back(pItem); + addItemToLinked(pItem); // add item normalized text if (!normalizedText.isEmpty()) { @@ -764,7 +761,7 @@ void FiguredBass::endEdit(EditData& ed) } // if all items parsed and text is styled, replaced entered text with normalized text if (m_items.size()) { - setXmlText(normalizedText); + undoChangeProperty(Pid::TEXT, normalizedText); } score()->startCmd(); @@ -877,6 +874,67 @@ PropertyValue FiguredBass::propertyDefault(Pid id) const return TextBase::propertyDefault(id); } +void FiguredBass::clearItems() +{ + const std::list links = linkList(); + for (EngravingObject* linkedObject : links) { + if (!linkedObject || !linkedObject->isFiguredBass()) { + continue; + } + Score* linkedScore = linkedObject->score(); + FiguredBass* linkedFb = toFiguredBass(linkedObject); + for (FiguredBassItem* fbItem : linkedFb->items()) { + linkedScore->undoRemoveElement(fbItem); + } + linkedFb->m_items.clear(); + } +} + +void FiguredBass::addItemToLinked(FiguredBassItem* item) +{ + const std::list links = linkList(); + for (EngravingObject* linkedObject : links) { + if (!linkedObject || !linkedObject->isFiguredBass()) { + continue; + } + Score* linkedScore = linkedObject->score(); + if (linkedObject == this) { + item->setTrack(track()); + item->setParent(this); + m_items.push_back(item); + score()->undo(new AddElement(item)); + } else { + FiguredBass* linkedFb = toFiguredBass(linkedObject); + FiguredBassItem* itemClone = item->clone(); + + itemClone->linkTo(item); + itemClone->setTrack(linkedFb->track()); + itemClone->setParent(linkedFb); + itemClone->setScore(linkedFb->score()); + linkedFb->appendItem(itemClone); + linkedScore->undo(new AddElement(itemClone)); + } + } +} + +void FiguredBass::remove(EngravingItem* item) +{ + switch (item->type()) { + case ElementType::FIGURED_BASS_ITEM: + { + auto i = find(m_items.begin(), m_items.end(), item); + if (i == m_items.end()) { + LOGD("FiguredBass::remove(): cannot find %s", item->typeName()); + break; + } + m_items.erase(i); + break; + } + default: + EngravingItem::remove(item); + } +} + //--------------------------------------------------------- // STATIC FUNCTION // adding a new FiguredBass to a Segment; @@ -1182,7 +1240,7 @@ FiguredBass* Score::addFiguredBass() } FiguredBass* fb; - bool bNew; + bool bNew = true; if (el->isNote()) { ChordRest* cr = toNote(el)->chord(); fb = FiguredBass::addFiguredBassToSegment(cr->segment(), cr->staffIdx() * VOICES, Fraction(0, 1), &bNew); diff --git a/src/engraving/dom/figuredbass.h b/src/engraving/dom/figuredbass.h index 76010ba9859eb..9fc2246fb1c21 100644 --- a/src/engraving/dom/figuredbass.h +++ b/src/engraving/dom/figuredbass.h @@ -91,6 +91,7 @@ class FiguredBass; class FiguredBassItem final : public EngravingItem { OBJECT_ALLOCATOR(engraving, FiguredBassItem) + DECLARE_CLASSOF(ElementType::FIGURED_BASS_ITEM) public: enum class Modifier : char { @@ -292,6 +293,9 @@ class FiguredBass final : public TextBase size_t itemsCount() const { return m_items.size(); } void appendItem(FiguredBassItem* item) { m_items.push_back(item); } const std::vector& items() const { return m_items; } + void clearItems(); + void addItemToLinked(FiguredBassItem* item); + virtual void remove(EngravingItem* item) override; // the array of configured fonts static const std::vector& FBFonts(); diff --git a/src/engraving/types/types.h b/src/engraving/types/types.h index 0f14835634e3c..56b317b513d91 100644 --- a/src/engraving/types/types.h +++ b/src/engraving/types/types.h @@ -107,6 +107,7 @@ enum class ElementType { HOOK, LYRICS, FIGURED_BASS, + FIGURED_BASS_ITEM, MARKER, JUMP, FINGERING, diff --git a/src/engraving/types/typesconv.cpp b/src/engraving/types/typesconv.cpp index cfc131755a225..c46855981d5c3 100644 --- a/src/engraving/types/typesconv.cpp +++ b/src/engraving/types/typesconv.cpp @@ -202,6 +202,7 @@ static const std::vector > ELEMENT_TYPES = { { ElementType::HOOK, "Hook", TranslatableString("engraving", "Flag") }, // internally called "Hook", but "Flag" in SMuFL, so here externally too { ElementType::LYRICS, "Lyrics", TranslatableString("engraving", "Lyrics") }, { ElementType::FIGURED_BASS, "FiguredBass", TranslatableString("engraving", "Figured bass") }, + { ElementType::FIGURED_BASS_ITEM, "FiguredBassItem", TranslatableString("engraving", "Figured bass item") }, { ElementType::MARKER, "Marker", TranslatableString("engraving", "Marker") }, { ElementType::JUMP, "Jump", TranslatableString("engraving", "Jump") }, { ElementType::FINGERING, "Fingering", TranslatableString("engraving", "Fingering") },