fix #292474 ambitus crash in plugins
Resolves: https://musescore.org/en/node/292474
This also resolves this issue reported in the forum: https://musescore.org/en/node/294734
It was achieved by extending plugin functionalities from commit c77d904eaa
. By adding:
* Support for elements that were causing application to crash such as: symbol, fingering, bend, notehead (note level), and clef and ambitus.
* You can now add and remove elements from notes using `Note::add()` and `Note::remove()`.
This commit is contained in:
parent
417f33bc88
commit
99d3dd9ec9
3 changed files with 153 additions and 4 deletions
|
@ -172,7 +172,7 @@ void Cursor::add(Element* wrapped)
|
|||
|
||||
// Ensure that the object has the expected ownership
|
||||
if (wrapped->ownership() == Ownership::SCORE) {
|
||||
qWarning("Chord::add: Cannot add this element. The element is already part of the score.");
|
||||
qWarning("Cursor::add: Cannot add this element. The element is already part of the score.");
|
||||
return; // Don't allow operation.
|
||||
}
|
||||
|
||||
|
@ -197,6 +197,7 @@ void Cursor::add(Element* wrapped)
|
|||
}
|
||||
else {
|
||||
switch (s->type()) {
|
||||
// To be added at measure level
|
||||
case ElementType::MEASURE_NUMBER:
|
||||
case ElementType::SPACER:
|
||||
case ElementType::JUMP:
|
||||
|
@ -210,6 +211,7 @@ void Cursor::add(Element* wrapped)
|
|||
break;
|
||||
}
|
||||
|
||||
// To be added at chord level
|
||||
case ElementType::NOTE:
|
||||
case ElementType::ARPEGGIO:
|
||||
case ElementType::TREMOLO:
|
||||
|
@ -221,8 +223,10 @@ void Cursor::add(Element* wrapped)
|
|||
Chord::addInternal(toChord(curElement), s);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
|
||||
// To be added at chord/rest level
|
||||
case ElementType::LYRICS: {
|
||||
Ms::Element* curElement = currentElement();
|
||||
if (curElement->isChordRest()) {
|
||||
|
@ -232,7 +236,53 @@ void Cursor::add(Element* wrapped)
|
|||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
// To be added to a note
|
||||
case ElementType::SYMBOL:
|
||||
case ElementType::FINGERING:
|
||||
case ElementType::BEND:
|
||||
case ElementType::NOTEHEAD: {
|
||||
Ms::Element* curElement = currentElement();
|
||||
if (curElement->isChord()) {
|
||||
Ms::Chord* chord = toChord(curElement);
|
||||
Ms::Note* note = nullptr;
|
||||
if (chord->notes().size() > 0) {
|
||||
// Get first note from chord to add element
|
||||
note = chord->notes().front();
|
||||
}
|
||||
if (note) {
|
||||
Note::addInternal(note, s);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// To be added to a segment (clef subtype)
|
||||
case ElementType::CLEF:
|
||||
case ElementType::AMBITUS: {
|
||||
Ms::Element* parent = nullptr;
|
||||
// Find backwards first measure containing a clef
|
||||
for (Ms::Measure* m = _segment->measure(); m != 0; m = m->prevMeasure()) {
|
||||
Ms::Segment* seg = m->findSegment(SegmentType::Clef | SegmentType::HeaderClef, m->tick());
|
||||
if (seg != 0) {
|
||||
parent = m->undoGetSegmentR(s->isAmbitus() ? SegmentType::Ambitus : seg->segmentType(), Fraction(0,1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parent && parent->isSegment()) {
|
||||
if (s->isClef()) {
|
||||
Ms::Clef* clef = toClef(s);
|
||||
if (clef->clefType() == Ms::ClefType::INVALID) {
|
||||
clef->setClefType(Ms::ClefType::G);
|
||||
}
|
||||
}
|
||||
s->setParent(parent);
|
||||
s->setTrack(_track);
|
||||
_score->undoAddElement(s);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default: // All others will be added to the current segment
|
||||
_score->undoAddElement(s);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -70,6 +70,93 @@ void Note::setTpc(int val)
|
|||
set(Pid::TPC2, val);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Note::isChildAllowed
|
||||
/// Check if element type can be a child of note.
|
||||
/// \since MuseScore 3.3.3
|
||||
//---------------------------------------------------------
|
||||
|
||||
bool Note::isChildAllowed(Ms::ElementType elementType)
|
||||
{
|
||||
switch(elementType) {
|
||||
case ElementType::NOTEHEAD:
|
||||
case ElementType::NOTEDOT:
|
||||
case ElementType::FINGERING:
|
||||
case ElementType::SYMBOL:
|
||||
case ElementType::IMAGE:
|
||||
case ElementType::TEXT:
|
||||
case ElementType::BEND:
|
||||
case ElementType::TIE:
|
||||
case ElementType::ACCIDENTAL:
|
||||
case ElementType::TEXTLINE:
|
||||
case ElementType::GLISSANDO:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Note::add
|
||||
/// \since MuseScore 3.3.3
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Note::add(Ms::PluginAPI::Element* wrapped)
|
||||
{
|
||||
Ms::Element* s = wrapped ? wrapped->element() : nullptr;
|
||||
if (s)
|
||||
{
|
||||
// Ensure that the object has the expected ownership
|
||||
if (wrapped->ownership() == Ownership::SCORE) {
|
||||
qWarning("Note::add: Cannot add this element. The element is already part of the score.");
|
||||
return; // Don't allow operation.
|
||||
}
|
||||
// Score now owns the object.
|
||||
wrapped->setOwnership(Ownership::SCORE);
|
||||
|
||||
addInternal(note(), s);
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Note::addInternal
|
||||
/// \since MuseScore 3.3.3
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Note::addInternal(Ms::Note* note, Ms::Element* s)
|
||||
{
|
||||
// Provide parentage for element.
|
||||
s->setParent(note);
|
||||
s->setTrack(note->track());
|
||||
|
||||
if (s && isChildAllowed(s->type())) {
|
||||
// Create undo op and add the element.
|
||||
toScore(note->score())->undoAddElement(s);
|
||||
}
|
||||
else if (s) {
|
||||
qDebug("Note::add() not impl. %s", s->name());
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Note::remove
|
||||
/// \since MuseScore 3.3.3
|
||||
//---------------------------------------------------------
|
||||
|
||||
void Note::remove(Ms::PluginAPI::Element* wrapped)
|
||||
{
|
||||
Ms::Element* s = wrapped->element();
|
||||
if (!s)
|
||||
qWarning("PluginAPI::Note::remove: Unable to retrieve element. %s", qPrintable(wrapped->name()));
|
||||
else if (s->parent() != note())
|
||||
qWarning("PluginAPI::Note::remove: The element is not a child of this note. Use removeElement() instead.");
|
||||
else if (isChildAllowed(s->type()))
|
||||
note()->score()->deleteItem(s); // Create undo op and remove the element.
|
||||
else
|
||||
qDebug("Note::remove() not impl. %s", s->name());
|
||||
}
|
||||
|
||||
//---------------------------------------------------------
|
||||
// Chord::setPlayEventType
|
||||
//---------------------------------------------------------
|
||||
|
@ -129,11 +216,13 @@ void Chord::addInternal(Ms::Chord* chord, Ms::Element* s)
|
|||
void Chord::remove(Ms::PluginAPI::Element* wrapped)
|
||||
{
|
||||
Ms::Element* s = wrapped->element();
|
||||
if (s->parent() != chord())
|
||||
if (!s)
|
||||
qWarning("PluginAPI::Chord::remove: Unable to retrieve element. %s", qPrintable(wrapped->name()));
|
||||
else if (s->parent() != chord())
|
||||
qWarning("PluginAPI::Chord::remove: The element is not a child of this chord. Use removeElement() instead.");
|
||||
else if (chord()->notes().size() <= 1 && s->type() == ElementType::NOTE)
|
||||
qWarning("PluginAPI::Chord::remove: Removal of final note is not allowed.");
|
||||
else if (s)
|
||||
else
|
||||
chord()->score()->deleteItem(s); // Create undo op and remove the element.
|
||||
}
|
||||
|
||||
|
|
|
@ -476,11 +476,21 @@ class Note : public Element {
|
|||
Ms::AccidentalType accidentalType() { return note()->accidentalType(); }
|
||||
void setAccidentalType(Ms::AccidentalType t) { note()->setAccidentalType(t); }
|
||||
Ms::NoteType noteType() { return note()->noteType(); }
|
||||
|
||||
static void addInternal(Ms::Note* note, Ms::Element* el);
|
||||
static bool isChildAllowed(Ms::ElementType elementType);
|
||||
/// \endcond
|
||||
|
||||
/// Creates a PlayEvent object for use in Javascript.
|
||||
/// \since MuseScore 3.3
|
||||
Q_INVOKABLE Ms::PluginAPI::PlayEvent* createPlayEvent() { return playEventWrap(new NoteEvent(), nullptr); }
|
||||
|
||||
/// Add to a note's elements.
|
||||
/// \since MuseScore 3.3.3
|
||||
Q_INVOKABLE void add(Ms::PluginAPI::Element* wrapped);
|
||||
/// Remove a note's element.
|
||||
/// \since MuseScore 3.3.3
|
||||
Q_INVOKABLE void remove(Ms::PluginAPI::Element* wrapped);
|
||||
};
|
||||
|
||||
//---------------------------------------------------------
|
||||
|
|
Loading…
Reference in a new issue