Line data Source code
1 : /*
2 : * SPDX-License-Identifier: GPL-3.0-only
3 : * MuseScore-Studio-CLA-applies
4 : *
5 : * MuseScore Studio
6 : * Music Composition & Notation
7 : *
8 : * Copyright (C) 2021 MuseScore Limited and others
9 : *
10 : * This program is free software: you can redistribute it and/or modify
11 : * it under the terms of the GNU General Public License version 3 as
12 : * published by the Free Software Foundation.
13 : *
14 : * This program is distributed in the hope that it will be useful,
15 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 : * GNU General Public License for more details.
18 : *
19 : * You should have received a copy of the GNU General Public License
20 : * along with this program. If not, see <https://www.gnu.org/licenses/>.
21 : */
22 :
23 : #include "chord.h"
24 :
25 : #include <cmath>
26 : #include <vector>
27 :
28 : #include "containers.h"
29 :
30 : #include "../editing/addremoveelement.h"
31 : #include "../editing/editchord.h"
32 : #include "../editing/editnote.h"
33 : #include "../editing/navigation.h"
34 :
35 : #include "accidental.h"
36 : #include "arpeggio.h"
37 : #include "chordbracket.h"
38 : #include "articulation.h"
39 : #include "beam.h"
40 : #include "chordline.h"
41 : #include "dom/parenthesis.h"
42 : #include "drumset.h"
43 : #include "factory.h"
44 : #include "guitarbend.h"
45 : #include "hook.h"
46 : #include "key.h"
47 : #include "ledgerline.h"
48 : #include "measure.h"
49 : #include "mscore.h"
50 : #include "note.h"
51 : #include "notedot.h"
52 : #include "noteevent.h"
53 : #include "noteline.h"
54 : #include "ornament.h"
55 : #include "part.h"
56 : #include "rest.h"
57 : #include "score.h"
58 : #include "segment.h"
59 : #include "staff.h"
60 : #include "stafftype.h"
61 : #include "stem.h"
62 : #include "stemslash.h"
63 : #include "stringdata.h"
64 : #include "system.h"
65 : #include "tie.h"
66 : #include "tremolosinglechord.h"
67 : #include "tremolotwochord.h"
68 : #include "trill.h"
69 : #include "tuplet.h"
70 : #include "utils.h"
71 :
72 : #ifndef ENGRAVING_NO_ACCESSIBILITY
73 : #include "accessibility/accessibleitem.h"
74 : #endif
75 :
76 : #include "log.h"
77 :
78 : using namespace mu;
79 : using namespace mu::engraving;
80 :
81 : namespace mu::engraving {
82 212 : NoteParenthesisInfo::NoteParenthesisInfo (Parenthesis* lParen, Parenthesis* rParen, std::vector<Note*> nList)
83 212 : : m_leftParen(lParen), m_rightParen(rParen), m_notes(nList)
84 : {
85 212 : std::sort(m_notes.begin(), m_notes.end(), noteIsBefore);
86 212 : }
87 :
88 174 : NoteParenthesisInfo::~NoteParenthesisInfo()
89 : {
90 174 : delete m_leftParen;
91 174 : delete m_rightParen;
92 174 : }
93 :
94 9 : void NoteParenthesisInfo::insertNote(Note* note)
95 : {
96 9 : m_notes.insert(std::upper_bound(m_notes.begin(), m_notes.end(), note, noteIsBefore), note);
97 9 : }
98 :
99 12 : void NoteParenthesisInfo::removeNote(Note* note)
100 : {
101 12 : muse::remove(m_notes, note);
102 12 : }
103 :
104 : //---------------------------------------------------------
105 : // upNote
106 : //---------------------------------------------------------
107 :
108 963630 : Note* Chord::upNote() const
109 : {
110 963630 : assert(!m_notes.empty());
111 :
112 963630 : Note* result = m_notes.back();
113 963630 : const Staff* stf = staff();
114 963630 : if (!stf) {
115 0 : return result;
116 : }
117 :
118 963630 : const StaffType* st = stf->staffTypeForElement(this);
119 963630 : if (st->isDrumStaff()) {
120 39670 : for (Note* n : m_notes) {
121 20449 : if (n->line() < result->line()) {
122 0 : result = n;
123 : }
124 : }
125 944409 : } else if (st->isTabStaff()) {
126 2349 : int line = st->lines(); // start at bottom line
127 : int noteLine;
128 : // scan each note: if TAB strings are not in sequential order,
129 : // visual order of notes might not correspond to pitch order
130 5301 : for (Note* n : m_notes) {
131 2952 : if (n->shouldHideFret()) {
132 2 : continue;
133 : }
134 2950 : noteLine = st->physStringToVisual(n->string());
135 2950 : if (noteLine < line) {
136 2931 : line = noteLine;
137 2931 : result = n;
138 : }
139 : }
140 : }
141 963630 : return result;
142 : }
143 :
144 : //---------------------------------------------------------
145 : // downNote
146 : //---------------------------------------------------------
147 :
148 935842 : Note* Chord::downNote() const
149 : {
150 935842 : assert(!m_notes.empty());
151 :
152 935842 : Note* result = m_notes.front();
153 935842 : const Staff* stf = staff();
154 935842 : if (!stf) {
155 0 : return result;
156 : }
157 :
158 935842 : const StaffType* st = stf->staffTypeForElement(this);
159 935842 : if (st->isDrumStaff()) {
160 28527 : for (Note* n : m_notes) {
161 14653 : if (n->line() > result->line()) {
162 0 : result = n;
163 : }
164 : }
165 921968 : } else if (st->isTabStaff()) {
166 1322 : int line = 0; // start at top line
167 : int noteLine;
168 : // scan each note: if TAB strings are not in sequential order,
169 : // visual order of notes might not correspond to pitch order
170 3095 : for (Note* n : m_notes) {
171 1773 : if (n->shouldHideFret()) {
172 4 : continue;
173 : }
174 1769 : noteLine = st->physStringToVisual(n->string());
175 1769 : if (noteLine > line) {
176 1055 : line = noteLine;
177 1055 : result = n;
178 : }
179 : }
180 : }
181 935842 : return result;
182 : }
183 :
184 : //---------------------------------------------------------
185 : // upLine / downLine
186 : //---------------------------------------------------------
187 :
188 386588 : int Chord::upLine() const
189 : {
190 386588 : return onTabStaff() ? upString() * 2 : upNote()->line();
191 : }
192 :
193 374751 : int Chord::downLine() const
194 : {
195 374751 : return onTabStaff() ? downString() * 2 : downNote()->line();
196 : }
197 :
198 : //---------------------------------------------------------
199 : // upString / downString
200 : //
201 : // return the topmost / bottommost string used by chord
202 : // Top and bottom refer to the DRAWN position, not the position in the instrument
203 : // (i.e., upside-down TAB are taken into account)
204 : //
205 : // If no staff, always return 0
206 : // If staff is not a TAB, always returns TOP and BOTTOM staff lines
207 : //---------------------------------------------------------
208 :
209 979 : int Chord::upString() const
210 : {
211 : // if no staff or staff not a TAB, return 0 (=topmost line)
212 979 : const Staff* st = staff();
213 979 : if (!st) {
214 0 : return 0;
215 : }
216 :
217 979 : const StaffType* tab = st->staffTypeForElement(this);
218 979 : if (!tab->isTabStaff()) {
219 0 : return 0;
220 : }
221 :
222 979 : int line = tab->lines() - 1; // start at bottom line
223 : int noteLine;
224 : // scan each note: if TAB strings are not in sequential order,
225 : // visual order of notes might not correspond to pitch order
226 979 : size_t n = m_notes.size();
227 2221 : for (size_t i = 0; i < n; ++i) {
228 1242 : noteLine = tab->physStringToVisual(m_notes.at(i)->string());
229 1242 : if (noteLine < line) {
230 1068 : line = noteLine;
231 : }
232 : }
233 979 : return line;
234 : }
235 :
236 2284 : int Chord::downString() const
237 : {
238 2284 : const Staff* st = staff();
239 2284 : if (!st) { // if no staff, return 0
240 0 : return 0;
241 : }
242 :
243 2284 : const StaffType* tab = st->staffTypeForElement(this);
244 2284 : if (!tab->isTabStaff()) { // if staff not a TAB, return bottom line
245 0 : return st->lines(tick()) - 1;
246 : }
247 :
248 2284 : int line = 0; // start at top line
249 : int noteLine;
250 2284 : size_t n = m_notes.size();
251 4943 : for (size_t i = 0; i < n; ++i) {
252 2659 : noteLine = tab->physStringToVisual(m_notes.at(i)->string());
253 2659 : if (noteLine > line) {
254 1786 : line = noteLine;
255 : }
256 : }
257 2284 : return line;
258 : }
259 :
260 : //---------------------------------------------------------
261 : // noteDistances
262 : //---------------------------------------------------------
263 :
264 44780 : std::vector<int> Chord::noteDistances() const
265 : {
266 44780 : const StaffType* staffType = this->staffType();
267 44780 : assert(staffType);
268 44780 : bool isTabStaff = staffType->isTabStaff();
269 44780 : int staffMiddleLine = staffType->middleLine();
270 :
271 44780 : std::vector<int> distances;
272 44780 : distances.reserve(m_notes.size());
273 95827 : for (Note* note : m_notes) {
274 51047 : int noteLine = isTabStaff ? note->string() : note->line();
275 51047 : distances.push_back(noteLine - staffMiddleLine);
276 : }
277 44780 : return distances;
278 0 : }
279 :
280 : //---------------------------------------------------------
281 : // Chord
282 : //---------------------------------------------------------
283 :
284 30391 : Chord::Chord(DummyParentOr<Segment> parent)
285 30391 : : ChordRest(ElementType::CHORD, parent)
286 : {
287 30391 : m_stem = 0;
288 30391 : m_hook = 0;
289 30391 : m_stemDirection = DirectionV::AUTO;
290 30391 : m_arpeggio = 0;
291 30391 : m_spanArpeggio = 0;
292 30391 : m_endsNoteAnchoredLine = false;
293 30391 : m_noteType = NoteType::NORMAL;
294 30391 : m_stemSlash = 0;
295 30391 : m_noStem = false;
296 30391 : m_showStemSlash = m_noteType == NoteType::ACCIACCATURA;
297 30391 : m_playEventType = PlayEventType::Auto;
298 30391 : m_spaceLw = 0.;
299 30391 : m_spaceRw = 0.;
300 30391 : m_crossMeasure = CrossMeasure::UNKNOWN;
301 30391 : m_graceIndex = 0;
302 30391 : m_combineVoice = AutoOnOff::AUTO;
303 30391 : }
304 :
305 3512 : Chord::Chord(const Chord& c, bool link)
306 3512 : : ChordRest(c, link)
307 : {
308 3512 : if (link) {
309 1037 : score()->undo(new Link(this, const_cast<Chord*>(&c)));
310 : }
311 :
312 8989 : for (Note* onote : c.m_notes) {
313 5477 : Note* nnote = Factory::copyNote(*onote, link);
314 5477 : add(nnote);
315 : }
316 3535 : for (Chord* gn : c.graceNotes()) {
317 23 : Chord* nc = new Chord(*gn, link);
318 23 : add(nc);
319 : }
320 3600 : for (Articulation* a : c.m_articulations) { // make deep copy
321 88 : Articulation* na = a->clone();
322 88 : if (link) {
323 27 : score()->undo(new Link(na, a));
324 : }
325 88 : na->setOwnershipParent(this);
326 88 : na->setTrack(track());
327 88 : m_articulations.push_back(na);
328 : }
329 3512 : m_stem = 0;
330 3512 : m_hook = 0;
331 3512 : m_endsNoteAnchoredLine = false;
332 3512 : m_arpeggio = 0;
333 3512 : m_stemSlash = 0;
334 :
335 3512 : m_spanArpeggio = c.m_spanArpeggio;
336 3512 : m_graceIndex = c.m_graceIndex;
337 3512 : m_noStem = c.m_noStem;
338 3512 : m_showStemSlash = c.m_showStemSlash;
339 3512 : m_playEventType = c.m_playEventType;
340 3512 : m_stemDirection = c.m_stemDirection;
341 3512 : m_noteType = c.m_noteType;
342 3512 : m_crossMeasure = CrossMeasure::UNKNOWN;
343 3512 : m_combineVoice = c.m_combineVoice;
344 :
345 3512 : if (c.m_stem) {
346 2514 : add(Factory::copyStem(*(c.m_stem)));
347 : }
348 3512 : if (c.m_hook) {
349 428 : add(new Hook(*(c.m_hook)));
350 : }
351 3512 : if (c.m_stemSlash) {
352 0 : add(Factory::copyStemSlash(*(c.m_stemSlash)));
353 : }
354 3512 : if (c.m_arpeggio) {
355 22 : Arpeggio* a = c.m_arpeggio->isChordBracket() ? new ChordBracket(*toChordBracket(c.m_arpeggio)) : new Arpeggio(*(c.m_arpeggio));
356 22 : add(a);
357 22 : if (link) {
358 22 : score()->undo(new Link(a, const_cast<Arpeggio*>(c.m_arpeggio)));
359 : }
360 : }
361 :
362 3512 : if (c.m_tremoloSingleChord) {
363 2 : TremoloSingleChord* t = Factory::copyTremoloSingleChord(*(c.m_tremoloSingleChord));
364 2 : if (link) {
365 2 : score()->undo(new Link(t, const_cast<TremoloSingleChord*>(c.m_tremoloSingleChord)));
366 : }
367 2 : add(t);
368 3510 : } else if (c.m_tremoloTwoChord) {
369 14 : if (c.m_tremoloTwoChord->chord1() == &c) {
370 8 : TremoloTwoChord* t = Factory::copyTremoloTwoChord(*(c.m_tremoloTwoChord));
371 8 : if (link) {
372 4 : score()->undo(new Link(t, const_cast<TremoloTwoChord*>(c.m_tremoloTwoChord)));
373 : }
374 8 : t->setChords(this, nullptr);
375 8 : add(t);
376 : }
377 : }
378 :
379 3516 : for (EngravingItem* e : c.el()) {
380 4 : if (e->isChordLine()) {
381 4 : ChordLine* cl = toChordLine(e);
382 4 : ChordLine* ncl = Factory::copyChordLine(*cl);
383 4 : add(ncl);
384 4 : if (cl->note()) {
385 2 : ncl->setNote(findNote(cl->note()->pitch()));
386 : }
387 4 : if (link) {
388 4 : score()->undo(new Link(ncl, cl));
389 : }
390 : }
391 : }
392 :
393 3516 : for (EngravingItem* e : c.el()) {
394 4 : if (e->isChordBracket()) {
395 0 : EngravingItem* clonedChordBracket = e->linkedClone();
396 0 : add(clonedChordBracket);
397 : }
398 : }
399 :
400 3512 : if (!c.noteParentheses().empty()) {
401 12 : for (const NoteParenthesisInfo* info : c.noteParentheses()) {
402 6 : Parenthesis* newLeftParen = toParenthesis(info->leftParen()->clone());
403 6 : newLeftParen->setOwnershipParent(this);
404 6 : Parenthesis* newRightParen = toParenthesis(info->rightParen()->clone());
405 6 : newRightParen->setOwnershipParent(this);
406 :
407 6 : if (link && !info->leftParen()->generated()) {
408 2 : score()->undo(new Link(newLeftParen, info->leftParen()));
409 : }
410 6 : if (link && !info->rightParen()->generated()) {
411 2 : score()->undo(new Link(newRightParen, info->rightParen()));
412 : }
413 :
414 6 : std::vector<Note*> newNotes;
415 6 : newNotes.reserve(info->notes().size());
416 12 : for (Note* note : info->notes()) {
417 6 : newNotes.push_back(findNote(note->pitch()));
418 : }
419 :
420 6 : m_noteParens.push_back(new NoteParenthesisInfo(newLeftParen, newRightParen, newNotes));
421 6 : }
422 : }
423 3512 : }
424 :
425 : //---------------------------------------------------------
426 : // undoUnlink
427 : //---------------------------------------------------------
428 :
429 179 : void Chord::undoUnlink()
430 : {
431 179 : ChordRest::undoUnlink();
432 360 : for (Note* n : m_notes) {
433 181 : n->undoUnlink();
434 : }
435 181 : for (Chord* gn : graceNotes()) {
436 2 : gn->undoUnlink();
437 : }
438 188 : for (Articulation* a : m_articulations) {
439 9 : a->undoUnlink();
440 : }
441 : /* if (_glissando)
442 : _glissando->undoUnlink(); */
443 179 : if (m_arpeggio) {
444 1 : m_arpeggio->undoUnlink();
445 : }
446 :
447 179 : if (tremoloSingleChord()) {
448 0 : tremoloSingleChord()->undoUnlink();
449 : }
450 :
451 179 : for (EngravingItem* e : el()) {
452 0 : if (e->isChordLine()) {
453 0 : e->undoUnlink();
454 : }
455 : }
456 179 : }
457 :
458 : //---------------------------------------------------------
459 : // ~Chord
460 : //---------------------------------------------------------
461 :
462 60138 : Chord::~Chord()
463 : {
464 30069 : muse::DeleteAll(m_articulations);
465 :
466 30069 : if (tremoloTwoChord()) {
467 122 : if (tremoloTwoChord()->chord1() == this) {
468 62 : tremoloTwoChord()->setChord1(nullptr);
469 60 : } else if (tremoloTwoChord()->chord2() == this) {
470 60 : tremoloTwoChord()->setChord2(nullptr);
471 : }
472 : }
473 :
474 30069 : delete m_arpeggio;
475 30069 : delete m_stemSlash;
476 30069 : delete m_stem;
477 30069 : delete m_hook;
478 30069 : muse::DeleteAll(m_ledgerLines);
479 30069 : muse::DeleteAll(m_graceNotes);
480 30069 : muse::DeleteAll(m_notes);
481 30069 : muse::DeleteAll(m_noteParens);
482 60138 : }
483 :
484 : #ifndef ENGRAVING_NO_ACCESSIBILITY
485 0 : AccessibleItemPtr Chord::createAccessible()
486 : {
487 0 : return std::make_shared<AccessibleItem>(this, AccessibleItem::Group);
488 : }
489 :
490 : #endif
491 :
492 : //---------------------------------------------------------
493 : // noteHeadWidth
494 : //---------------------------------------------------------
495 :
496 195607 : double Chord::noteHeadWidth() const
497 : {
498 195607 : return score()->noteHeadWidth() * mag();
499 : }
500 :
501 : //---------------------------------------------------------
502 : // rightEdge
503 : //---------------------------------------------------------
504 :
505 0 : double Chord::rightEdge() const
506 : {
507 0 : double right = 0.0;
508 0 : for (Note* n : notes()) {
509 0 : right = std::max(right, x() + n->x() + n->bboxRightPos());
510 : }
511 :
512 0 : return right;
513 : }
514 :
515 5182 : TremoloType Chord::tremoloType() const
516 : {
517 5182 : if (tremoloSingleChord()) {
518 117 : return tremoloSingleChord()->tremoloType();
519 5065 : } else if (tremoloTwoChord()) {
520 22 : return tremoloTwoChord()->tremoloType();
521 : } else {
522 5043 : return TremoloType::INVALID_TREMOLO;
523 : }
524 : }
525 :
526 1138463 : TremoloTwoChord* Chord::tremoloTwoChord() const
527 : {
528 1138463 : return m_tremoloTwoChord;
529 : }
530 :
531 519362 : TremoloSingleChord* Chord::tremoloSingleChord() const
532 : {
533 519362 : return m_tremoloSingleChord;
534 : }
535 :
536 262 : void Chord::setTremoloTwoChord(TremoloTwoChord* tr, bool applyLogic)
537 : {
538 262 : if (m_tremoloTwoChord && tr && tr == m_tremoloTwoChord) {
539 74 : return;
540 : }
541 :
542 188 : if (m_tremoloTwoChord) {
543 30 : TDuration d;
544 30 : const Fraction f = ticks();
545 30 : if (f.numerator() > 0) {
546 30 : d = TDuration(f);
547 : } else {
548 0 : d = m_tremoloTwoChord->durationType();
549 0 : const int dots = d.dots();
550 0 : d = d.shift(1);
551 0 : d.setDots(dots);
552 : }
553 :
554 30 : setDurationType(d);
555 30 : Chord* other = m_tremoloTwoChord->chord1() == this ? m_tremoloTwoChord->chord2() : m_tremoloTwoChord->chord1();
556 30 : m_tremoloTwoChord = nullptr;
557 30 : if (other) {
558 10 : other->setTremoloTwoChord(nullptr);
559 : }
560 : }
561 188 : m_tremoloSingleChord = nullptr;
562 :
563 188 : if (tr && applyLogic) {
564 140 : TDuration d = tr->durationType();
565 140 : if (!d.isValid()) {
566 52 : d = durationType();
567 52 : const int dots = d.dots();
568 52 : d = d.shift(-1);
569 52 : d.setDots(dots);
570 52 : tr->setDurationType(d);
571 : }
572 :
573 140 : setDurationType(d);
574 140 : Chord* other = tr->chord1() == this ? tr->chord2() : tr->chord1();
575 140 : m_tremoloTwoChord = tr;
576 140 : if (other) {
577 102 : other->setTremoloTwoChord(tr);
578 : }
579 : }
580 :
581 188 : m_tremoloTwoChord = tr;
582 : }
583 :
584 166 : void Chord::setTremoloSingleChord(TremoloSingleChord* tr)
585 : {
586 166 : if (m_tremoloSingleChord && tr && tr == m_tremoloSingleChord) {
587 0 : return;
588 : }
589 :
590 166 : if (m_tremoloTwoChord) {
591 0 : TDuration d;
592 0 : const Fraction f = ticks();
593 0 : if (f.numerator() > 0) {
594 0 : d = TDuration(f);
595 : } else {
596 0 : d = m_tremoloTwoChord->durationType();
597 0 : const int dots = d.dots();
598 0 : d = d.shift(1);
599 0 : d.setDots(dots);
600 : }
601 :
602 0 : setDurationType(d);
603 0 : Chord* other = m_tremoloTwoChord->chord1() == this ? m_tremoloTwoChord->chord2() : m_tremoloTwoChord->chord1();
604 0 : m_tremoloTwoChord = nullptr;
605 0 : if (other) {
606 0 : other->setTremoloTwoChord(nullptr);
607 : }
608 : }
609 :
610 166 : m_tremoloSingleChord = tr;
611 : }
612 :
613 : //---------------------------------------------------------
614 : // add
615 : //---------------------------------------------------------
616 :
617 77380 : void Chord::add(EngravingItem* e)
618 : {
619 77380 : if (e->ownershipParent() != this) {
620 9802 : e->setOwnershipParent(this);
621 : }
622 77380 : e->setTrack(track());
623 77380 : switch (e->type()) {
624 41413 : case ElementType::NOTE:
625 : {
626 41413 : Note* note = toNote(e);
627 41413 : bool tab = staff() && staff()->isTabStaff(tick());
628 41413 : bool found = false;
629 :
630 46985 : for (unsigned idx = 0; idx < m_notes.size(); ++idx) {
631 10250 : if (tab) {
632 : // _notes should be sorted by string
633 116 : if (note->string() > m_notes[idx]->string()) {
634 9 : m_notes.insert(m_notes.begin() + idx, note);
635 9 : found = true;
636 9 : break;
637 : }
638 : } else {
639 : // _notes should be sorted by line position,
640 : // but it's often not yet possible since line is unknown
641 : // use pitch instead, and line as a second sort criteria.
642 10134 : if (note->pitch() <= m_notes[idx]->pitch()) {
643 4669 : if (note->pitch() == m_notes[idx]->pitch() && note->line() >= m_notes[idx]->line()) {
644 55 : m_notes.insert(m_notes.begin() + idx + 1, note);
645 : } else {
646 4614 : m_notes.insert(m_notes.begin() + idx, note);
647 : }
648 4669 : found = true;
649 4669 : break;
650 : }
651 : }
652 : }
653 41413 : if (!found) {
654 36735 : m_notes.push_back(note);
655 : }
656 41413 : note->connectTiedNotes();
657 41413 : if (voice() && measure() && note->visible()) {
658 2667 : measure()->setHasVoices(staffIdx(), true);
659 : }
660 : }
661 41413 : break;
662 86 : case ElementType::ARPEGGIO:
663 86 : m_arpeggio = toArpeggio(e);
664 86 : break;
665 0 : case ElementType::CHORD_BRACKET:
666 0 : addEl(e);
667 0 : break;
668 41 : case ElementType::TREMOLO_TWOCHORD:
669 41 : setTremoloTwoChord(item_cast<TremoloTwoChord*>(e));
670 41 : break;
671 77 : case ElementType::TREMOLO_SINGLECHORD:
672 77 : setTremoloSingleChord(item_cast<TremoloSingleChord*>(e));
673 77 : break;
674 0 : case ElementType::GLISSANDO:
675 0 : m_endsNoteAnchoredLine = true;
676 0 : break;
677 30023 : case ElementType::STEM:
678 30023 : assert(!m_stem);
679 30023 : m_stem = toStem(e);
680 30023 : break;
681 1697 : case ElementType::HOOK:
682 1697 : m_hook = toHook(e);
683 1697 : break;
684 158 : case ElementType::CHORDLINE:
685 158 : addEl(e);
686 158 : break;
687 142 : case ElementType::STEM_SLASH:
688 142 : assert(!m_stemSlash);
689 142 : m_stemSlash = toStemSlash(e);
690 142 : break;
691 671 : case ElementType::CHORD:
692 : {
693 671 : Chord* gc = toChord(e);
694 671 : assert(gc->noteType() != NoteType::NORMAL);
695 671 : size_t idx = gc->graceIndex();
696 671 : gc->setFlag(ElementFlag::MOVABLE, true);
697 671 : m_graceNotes.insert(m_graceNotes.begin() + idx, gc);
698 : }
699 671 : break;
700 0 : case ElementType::LEDGER_LINE:
701 0 : ASSERT_X("Chord::add ledgerline");
702 : break;
703 1289 : case ElementType::ARTICULATION:
704 : case ElementType::ORNAMENT:
705 : case ElementType::TAPPING:
706 : {
707 1289 : Articulation* a = toArticulation(e);
708 1289 : if (a->layoutCloseToNote()) {
709 417 : if (a->isStaccato()) {
710 : // staccato is always the first articulation
711 295 : m_articulations.insert(m_articulations.begin(), a);
712 : } else {
713 122 : auto i = m_articulations.begin();
714 151 : while (i != m_articulations.end() && (*i)->layoutCloseToNote()) {
715 29 : i++;
716 : }
717 122 : m_articulations.insert(i, a);
718 : }
719 : } else {
720 872 : m_articulations.push_back(a);
721 : }
722 : }
723 1289 : break;
724 1783 : default:
725 1783 : ChordRest::add(e);
726 1783 : return;
727 : }
728 :
729 75597 : e->added();
730 : }
731 :
732 : //---------------------------------------------------------
733 : // remove
734 : //---------------------------------------------------------
735 :
736 1237 : void Chord::remove(EngravingItem* e)
737 : {
738 1237 : if (!e) {
739 0 : return;
740 : }
741 :
742 1237 : switch (e->type()) {
743 376 : case ElementType::NOTE:
744 : {
745 376 : Note* note = toNote(e);
746 376 : auto i = std::find(m_notes.begin(), m_notes.end(), note);
747 376 : if (i != m_notes.end()) {
748 376 : m_notes.erase(i);
749 376 : note->disconnectTiedNotes();
750 376 : for (Spanner* s : note->spannerBack()) {
751 0 : note->removeSpannerBack(s);
752 : }
753 376 : for (Spanner* s : note->spannerFor()) {
754 0 : note->removeSpannerFor(s);
755 : }
756 1128 : EditChord::removeChordParentheses(this, { note });
757 : } else {
758 0 : LOGD("Chord::remove() note %p not found!", e);
759 : }
760 376 : if (voice() && measure() && note->visible()) {
761 99 : measure()->checkMultiVoices(staffIdx());
762 : }
763 : }
764 376 : break;
765 :
766 0 : case ElementType::ARPEGGIO:
767 0 : if (m_spanArpeggio == m_arpeggio) {
768 0 : m_spanArpeggio = nullptr;
769 : }
770 0 : m_arpeggio = nullptr;
771 0 : break;
772 0 : case ElementType::CHORD_BRACKET:
773 0 : removeEl(e);
774 0 : break;
775 1 : case ElementType::TREMOLO_TWOCHORD:
776 1 : setTremoloTwoChord(nullptr);
777 1 : break;
778 0 : case ElementType::TREMOLO_SINGLECHORD:
779 0 : setTremoloSingleChord(nullptr);
780 0 : break;
781 0 : case ElementType::GLISSANDO:
782 0 : m_endsNoteAnchoredLine = false;
783 0 : break;
784 567 : case ElementType::STEM:
785 567 : m_stem = 0;
786 567 : break;
787 30 : case ElementType::HOOK:
788 30 : m_hook = 0;
789 30 : break;
790 11 : case ElementType::STEM_SLASH:
791 11 : assert(m_stemSlash);
792 11 : if (m_stemSlash->selected() && score()) {
793 0 : score()->deselect(m_stemSlash);
794 : }
795 11 : m_stemSlash = 0;
796 11 : break;
797 12 : case ElementType::CHORDLINE:
798 12 : removeEl(e);
799 12 : break;
800 9 : case ElementType::CHORD:
801 : {
802 9 : auto i = std::find(m_graceNotes.begin(), m_graceNotes.end(), toChord(e));
803 9 : IF_ASSERT_FAILED(i != m_graceNotes.end()) {
804 0 : break;
805 : }
806 9 : Chord* grace = *i;
807 9 : grace->setGraceIndex(i - m_graceNotes.begin());
808 9 : m_graceNotes.erase(i);
809 : }
810 9 : break;
811 213 : case ElementType::ARTICULATION:
812 : case ElementType::ORNAMENT:
813 : case ElementType::TAPPING:
814 : {
815 213 : Articulation* a = toArticulation(e);
816 213 : if (!muse::remove(m_articulations, a)) {
817 0 : LOGD("Chord::remove(): articulation not found");
818 : }
819 : }
820 213 : break;
821 0 : case ElementType::PARENTHESIS: {
822 0 : NoteParenthesisInfo* parenInfo = findNoteParenthesisInfo(toParenthesis(e));
823 0 : IF_ASSERT_FAILED(parenInfo) {
824 0 : LOGD() << "Chord::remove(): This parenthesis does not belong to this chord";
825 0 : return;
826 : }
827 0 : EditChord::removeChordParentheses(this, parenInfo->notes());
828 0 : break;
829 : }
830 : break;
831 18 : default:
832 18 : ChordRest::remove(e);
833 18 : return;
834 : }
835 :
836 1219 : e->removed();
837 : }
838 :
839 : //---------------------------------------------------------
840 : // maxHeadWidth
841 : //---------------------------------------------------------
842 :
843 0 : double Chord::maxHeadWidth() const
844 : {
845 : // determine max head width in chord
846 0 : double hw = 0;
847 0 : for (const Note* n : m_notes) {
848 0 : double t = n->headWidth();
849 0 : if (t > hw) {
850 0 : hw = t;
851 : }
852 : }
853 0 : return hw;
854 : }
855 :
856 : //---------------------------------------------------------
857 : // selectedNote
858 : //---------------------------------------------------------
859 :
860 0 : Note* Chord::selectedNote() const
861 : {
862 0 : Note* note = 0;
863 0 : size_t n = m_notes.size();
864 0 : for (size_t i = 0; i < n; ++i) {
865 0 : Note* currentNote = m_notes.at(i);
866 0 : if (currentNote->selected()) {
867 0 : if (note) {
868 0 : return 0;
869 : }
870 0 : note = currentNote;
871 : }
872 : }
873 0 : return note;
874 : }
875 :
876 : //---------------------------------------------------------
877 : // upPos
878 : //---------------------------------------------------------
879 :
880 3508 : double Chord::upPos() const
881 : {
882 3508 : return upNote()->pos().y();
883 : }
884 :
885 : //---------------------------------------------------------
886 : // downPos
887 : //---------------------------------------------------------
888 :
889 3497 : double Chord::downPos() const
890 : {
891 3497 : return downNote()->pos().y();
892 : }
893 :
894 0 : bool Chord::allNotesTiedToNext() const
895 : {
896 0 : Chord* tiedChord = nullptr;
897 0 : for (Note* note : m_notes) {
898 0 : if (!note->tieFor()) {
899 0 : return false;
900 : }
901 :
902 0 : Note* endNote = note->tieFor()->endNote();
903 0 : Chord* endChord = endNote ? endNote->chord() : nullptr;
904 0 : if (!endChord) {
905 0 : return false;
906 : }
907 :
908 0 : if (!tiedChord) {
909 0 : tiedChord = endChord;
910 0 : continue;
911 : }
912 :
913 0 : if (endChord != tiedChord) {
914 0 : return false;
915 : }
916 : }
917 :
918 0 : return true;
919 : }
920 :
921 8281 : bool Chord::allElementsInvisible() const
922 : {
923 8353 : for (EngravingObject* child : getChildren()) {
924 8321 : if (toEngravingItem(child)->visible()) {
925 8249 : return false;
926 : }
927 8281 : }
928 :
929 32 : for (Chord* grace : m_graceNotes) {
930 0 : if (!grace->allElementsInvisible()) {
931 0 : return false;
932 : }
933 : }
934 :
935 32 : return true;
936 : }
937 :
938 : //---------------------------------------------------------
939 : // processSiblings
940 : //---------------------------------------------------------
941 :
942 40053 : void Chord::processSiblings(std::function<void(EngravingItem*)> func, bool includeTemporarySiblings) const
943 : {
944 40053 : if (m_hook) {
945 649 : func(m_hook);
946 : }
947 40053 : if (m_stem) {
948 4561 : func(m_stem);
949 : }
950 40053 : if (m_stemSlash) {
951 90 : func(m_stemSlash);
952 : }
953 40053 : if (m_arpeggio) {
954 71 : func(m_arpeggio);
955 : }
956 40053 : if (m_tremoloTwoChord) {
957 16 : func(m_tremoloTwoChord);
958 : }
959 40053 : if (m_tremoloSingleChord) {
960 8 : func(m_tremoloSingleChord);
961 : }
962 40053 : if (includeTemporarySiblings) {
963 40160 : for (LedgerLine* ll : m_ledgerLines) {
964 108 : func(ll);
965 : }
966 : }
967 40222 : for (Articulation* a : m_articulations) {
968 169 : func(a);
969 : }
970 57741 : for (Note* note : m_notes) {
971 17688 : func(note);
972 : }
973 40133 : for (Chord* chord : m_graceNotes) { // process grace notes last, needed for correct shape calculation
974 80 : func(chord);
975 : }
976 40053 : }
977 :
978 : //---------------------------------------------------------
979 : // setTrack
980 : //---------------------------------------------------------
981 :
982 36708 : void Chord::setTrack(track_idx_t val)
983 : {
984 36708 : ChordRest::setTrack(val);
985 52438 : processSiblings([val](EngravingItem* e) { e->setTrack(val); }, true);
986 36708 : }
987 :
988 101857 : bool Chord::shouldCombineVoice() const
989 : {
990 101857 : return combineVoice() == AutoOnOff::ON || (combineVoice() == AutoOnOff::AUTO && style().styleB(Sid::combineVoice));
991 : }
992 :
993 1376 : bool Chord::combineVoice(const Chord* chord1, const Chord* chord2)
994 : {
995 1376 : return chord1->shouldCombineVoice() && chord2->shouldCombineVoice();
996 : }
997 :
998 : //---------------------------------------------------------
999 : // setScore
1000 : //---------------------------------------------------------
1001 :
1002 3344 : void Chord::setScore(Score* s)
1003 : {
1004 3344 : ChordRest::setScore(s);
1005 11052 : processSiblings([s](EngravingItem* e) { e->setScore(s); }, true);
1006 3344 : }
1007 :
1008 0 : Fraction Chord::endTickIncludingTied() const
1009 : {
1010 0 : const Chord* lastTied = this;
1011 0 : while (lastTied) {
1012 0 : const Chord* next = lastTied->nextTiedChord();
1013 0 : if (next) {
1014 0 : lastTied = next;
1015 : } else {
1016 0 : break;
1017 : }
1018 : }
1019 0 : return lastTied->endTick();
1020 : }
1021 :
1022 263 : Chord* Chord::prev() const
1023 : {
1024 263 : ChordRest* prev = Navigation::prevChordRest(const_cast<Chord*>(this));
1025 263 : if (prev && prev->isChord()) {
1026 257 : return toChord(prev);
1027 : }
1028 6 : return nullptr;
1029 : }
1030 :
1031 338 : Chord* Chord::next() const
1032 : {
1033 338 : ChordRest* next = Navigation::nextChordRest(const_cast<Chord*>(this));
1034 338 : if (next && next->isChord()) {
1035 219 : return toChord(next);
1036 : }
1037 119 : return nullptr;
1038 : }
1039 :
1040 7839 : void Chord::resizeLedgerLinesTo(size_t newSize)
1041 : {
1042 7839 : int ledgerLineCountDiff = static_cast<int>(newSize - m_ledgerLines.size());
1043 7839 : if (ledgerLineCountDiff > 0) {
1044 207911 : for (int i = 0; i < ledgerLineCountDiff; ++i) {
1045 202101 : m_ledgerLines.push_back(new LedgerLine(this));
1046 : }
1047 : } else {
1048 22039 : for (int i = 0; i < std::abs(ledgerLineCountDiff); ++i) {
1049 20010 : delete m_ledgerLines.back();
1050 20010 : m_ledgerLines.pop_back();
1051 : }
1052 : }
1053 :
1054 7839 : assert(m_ledgerLines.size() == newSize);
1055 7839 : }
1056 :
1057 30226 : void Chord::setBeamExtension(double extension)
1058 : {
1059 30226 : if (m_stem) {
1060 30226 : double baseLength = m_stem->absoluteFromSpatium(m_stem->baseLength());
1061 30226 : m_stem->setBaseLength(std::max(Spatium::fromAbsolute(baseLength + extension, spatium()), 0.0_sp));
1062 30226 : m_defaultStemLength = std::max(m_defaultStemLength + extension, m_stem->absoluteFromSpatium(m_stem->baseLength()));
1063 : }
1064 30226 : }
1065 :
1066 84067 : bool Chord::shouldHaveStem() const
1067 : {
1068 84067 : const Staff* staff = this->staff();
1069 84067 : const StaffType* staffType = staff ? staff->staffTypeForElement(this) : nullptr;
1070 :
1071 84067 : return !m_noStem
1072 83335 : && durationType().hasStem()
1073 159119 : && !(durationType().type() == DurationType::V_HALF && staffType && staffType->isTabStaff()
1074 417 : && staffType->minimStyle() == TablatureMinimStyle::NONE)
1075 74248 : && !(measure() && measure()->stemless(staffIdx()))
1076 251469 : && !(staffType && staffType->isTabStaff() && staffType->stemless());
1077 : }
1078 :
1079 34216 : bool Chord::shouldHaveHook() const
1080 : {
1081 34216 : return shouldHaveStem()
1082 63824 : && durationType().hooks() > 0
1083 2360 : && !beam()
1084 98040 : && !tremoloTwoChord();
1085 : }
1086 :
1087 22727 : void Chord::createStem()
1088 : {
1089 22727 : Stem* stem = Factory::createStem(this);
1090 22727 : stem->setGenerated(true);
1091 : //! score()->undoAddElement calls add(), which assigns this created stem to _stem
1092 22727 : score()->doUndoAddElement(stem);
1093 22727 : }
1094 :
1095 5203 : void Chord::removeStem()
1096 : {
1097 5203 : if (m_stem) {
1098 567 : score()->undoRemoveElement(m_stem);
1099 : }
1100 5203 : if (m_hook) {
1101 0 : score()->undoRemoveElement(m_hook);
1102 : }
1103 5203 : if (m_stemSlash) {
1104 0 : score()->undoRemoveElement(m_stemSlash);
1105 : }
1106 5203 : }
1107 :
1108 1269 : void Chord::createHook()
1109 : {
1110 1269 : Hook* hook = new Hook(this);
1111 1269 : hook->setGenerated(true);
1112 1269 : score()->doUndoAddElement(hook);
1113 1269 : }
1114 :
1115 : //---------------------------------------------------------
1116 : // underBeam: true, if grace note is placed under a beam.
1117 : //---------------------------------------------------------
1118 :
1119 0 : bool Chord::underBeam() const
1120 : {
1121 0 : if (m_noteType == NoteType::NORMAL) {
1122 0 : return false;
1123 : }
1124 0 : const Chord* cr = toChord(ownershipParent());
1125 0 : Beam* beam = cr->beam();
1126 0 : if (!beam || !cr->beam()->up()) {
1127 0 : return false;
1128 : }
1129 0 : size_t s = beam->elements().size();
1130 0 : if (isGraceBefore()) {
1131 0 : if (beam->elements()[0] != cr) {
1132 0 : return true;
1133 : }
1134 : }
1135 0 : if (isGraceAfter()) {
1136 0 : if (beam->elements()[s - 1] != cr) {
1137 0 : return true;
1138 : }
1139 : }
1140 0 : return false;
1141 : }
1142 :
1143 : //---------------------------------------------------------
1144 : // cmdUpdateNotes
1145 : //---------------------------------------------------------
1146 :
1147 59965 : void Chord::cmdUpdateNotes(AccidentalState* as, staff_idx_t staffIdx)
1148 : {
1149 : // TAB_STAFF is different, as each note has to be fretted
1150 : // in the context of the all of the chords of the whole segment
1151 :
1152 59965 : const Staff* st = staff();
1153 59965 : StaffGroup staffGroup = st->staffTypeForElement(this)->group();
1154 59965 : if (staffGroup == StaffGroup::TAB) {
1155 1426 : Fraction tick = this->tick();
1156 1426 : const StringData* stringData = originPart()->stringData(tick, st->idx());
1157 1486 : for (Chord* ch : graceNotes()) {
1158 60 : stringData->fretChords(ch);
1159 : }
1160 1426 : stringData->fretChords(this);
1161 1426 : return;
1162 : } else {
1163 : // if not tablature, use instrument->useDrumset to set staffGroup (to allow pitched to unpitched in same staff)
1164 58539 : staffGroup = originPart()->instrument(this->tick())->useDrumset() ? StaffGroup::PERCUSSION : StaffGroup::STANDARD;
1165 : }
1166 :
1167 : // PITCHED_ and PERCUSSION_STAFF can go note by note
1168 :
1169 58539 : if (staffGroup == StaffGroup::STANDARD) {
1170 57423 : const std::vector<Chord*> gnb(graceNotesBefore());
1171 58190 : for (Chord* ch : gnb) {
1172 767 : if (ch->vStaffIdx() != staffIdx) {
1173 133 : continue;
1174 : }
1175 634 : std::vector<Note*> notes(ch->notes()); // we need a copy!
1176 1358 : for (Note* note : notes) {
1177 724 : note->updateAccidental(as);
1178 : }
1179 634 : ch->sortNotes();
1180 634 : }
1181 57423 : if (vStaffIdx() == staffIdx) {
1182 46212 : std::vector<Note*> lnotes(notes()); // we need a copy!
1183 101085 : for (Note* note : lnotes) {
1184 54873 : if (note->tieBackNonPartial() && note->tpc() == note->tieBack()->startNote()->tpc()) {
1185 : // same pitch
1186 2119 : if (note->accidental() && note->accidental()->role() == AccidentalRole::AUTO) {
1187 : // not courtesy
1188 : // TODO: remove accidental only if note is not
1189 : // on new system
1190 30 : score()->undoRemoveElement(note->accidental());
1191 : }
1192 : }
1193 54873 : note->updateAccidental(as);
1194 : }
1195 47860 : for (Articulation* art : m_articulations) {
1196 1648 : if (!art->isOrnament()) {
1197 1340 : continue;
1198 : }
1199 308 : Ornament* ornament = toOrnament(art);
1200 308 : ornament->computeNotesAboveAndBelow(as);
1201 : }
1202 47993 : for (Spanner* spanner : startingSpanners()) {
1203 1781 : if (spanner->isTrill()) {
1204 113 : Ornament* ornament = toTrill(spanner)->ornament();
1205 113 : if (ornament) {
1206 113 : ornament->setOwnershipParent(this);
1207 113 : ornament->computeNotesAboveAndBelow(as);
1208 : }
1209 : }
1210 : }
1211 46212 : sortNotes();
1212 46212 : }
1213 57423 : const std::vector<Chord*> gna(graceNotesAfter());
1214 57673 : for (Chord* ch : gna) {
1215 250 : if (ch->vStaffIdx() != staffIdx) {
1216 23 : continue;
1217 : }
1218 227 : std::vector<Note*> notes(ch->notes()); // we need a copy!
1219 476 : for (Note* note : notes) {
1220 249 : note->updateAccidental(as);
1221 : }
1222 227 : ch->sortNotes();
1223 227 : }
1224 58539 : } else if (staffGroup == StaffGroup::PERCUSSION) {
1225 1116 : const Instrument* instrument = originPart()->instrument(this->tick());
1226 1116 : const Drumset* drumset = instrument->drumset();
1227 1116 : if (!drumset) {
1228 0 : LOGW("no drumset");
1229 : }
1230 1116 : updatePercussionNotes(this, drumset);
1231 1116 : sortNotes();
1232 : }
1233 : }
1234 :
1235 : //---------------------------------------------------------
1236 : // pagePos
1237 : //---------------------------------------------------------
1238 :
1239 261401 : PointF Chord::pagePos() const
1240 : {
1241 261401 : if (!isGrace()) {
1242 255096 : return EngravingItem::pagePos();
1243 : }
1244 :
1245 6305 : PointF p(pos());
1246 6305 : if (!ownershipParent()) {
1247 0 : return p;
1248 : }
1249 6305 : p.rx() = pageX();
1250 :
1251 6305 : const Chord* pc = toChord(ownershipParent());
1252 6305 : System* system = pc->segment()->system();
1253 6305 : if (!system) {
1254 3 : return p;
1255 : }
1256 6302 : p.ry() += system->staffYpage(vStaffIdx()) + staffOffsetY();
1257 6302 : return p;
1258 : }
1259 :
1260 : //---------------------------------------------------------
1261 : // scanElements
1262 : //---------------------------------------------------------
1263 :
1264 14250 : void Chord::scanElements(std::function<void(EngravingItem*)> func)
1265 : {
1266 14554 : for (Articulation* a : m_articulations) {
1267 304 : a->scanElements(func);
1268 : }
1269 14250 : if (m_hook) {
1270 1039 : func(m_hook);
1271 : }
1272 14250 : if (m_stem) {
1273 13610 : func(m_stem);
1274 : }
1275 14250 : if (m_stemSlash) {
1276 32 : func(m_stemSlash);
1277 : }
1278 14250 : if (m_arpeggio) {
1279 96 : func(m_arpeggio);
1280 : }
1281 14250 : if (m_tremoloTwoChord && (tremoloChordType() != TremoloChordType::TremoloSecondChord)) {
1282 4 : func(m_tremoloTwoChord);
1283 : }
1284 14250 : if (m_tremoloSingleChord) {
1285 27 : func(m_tremoloSingleChord);
1286 : }
1287 14250 : const Staff* st = staff();
1288 14250 : if ((st && st->showLedgerLines(tick())) || !st) { // also for palette
1289 18863 : for (LedgerLine* ll : m_ledgerLines) {
1290 4613 : func(ll);
1291 : }
1292 : }
1293 32590 : for (Note* note : m_notes) {
1294 18340 : note->scanElements(func);
1295 : }
1296 14348 : for (Chord* chord : m_graceNotes) {
1297 98 : chord->scanElements(func);
1298 : }
1299 14302 : for (EngravingItem* e : el()) {
1300 52 : e->scanElements(func);
1301 : }
1302 :
1303 14261 : for (auto& p : m_noteParens) {
1304 11 : p->leftParen()->scanElements(func);
1305 11 : p->rightParen()->scanElements(func);
1306 : }
1307 14250 : ChordRest::scanElements(func);
1308 14250 : }
1309 :
1310 463 : NoteParenthesisInfo* Chord::findNoteParenthesisInfo(const Parenthesis* paren)
1311 : {
1312 485 : for (NoteParenthesisInfo* infoPtr : m_noteParens) {
1313 485 : if (paren == infoPtr->leftParen() || paren == infoPtr->rightParen()) {
1314 463 : return infoPtr;
1315 : }
1316 : }
1317 :
1318 0 : return nullptr;
1319 : }
1320 :
1321 72261 : const NoteParenthesisInfo* Chord::findNoteParenthesisInfo(const Note* note) const
1322 : {
1323 72320 : for (const NoteParenthesisInfo* infoPtr : m_noteParens) {
1324 892 : for (const Note* parenNote : infoPtr->notes()) {
1325 833 : if (parenNote == note) {
1326 482 : return infoPtr;
1327 : }
1328 : }
1329 : }
1330 :
1331 71779 : DO_ASSERT(u"Parentheses are not in chord");
1332 71779 : return nullptr;
1333 : }
1334 :
1335 206 : void Chord::addNoteParenthesisInfo(NoteParenthesisInfo* noteParenInfo)
1336 : {
1337 206 : m_noteParens.push_back(noteParenInfo);
1338 206 : }
1339 :
1340 13 : void Chord::removeNoteParenthesisInfo(const NoteParenthesisInfo* noteParenInfo)
1341 : {
1342 13 : if (m_noteParens.empty()) {
1343 0 : return;
1344 : }
1345 :
1346 13 : if (!noteParenInfo) {
1347 0 : return;
1348 : }
1349 :
1350 13 : auto it = std::find_if(m_noteParens.begin(), m_noteParens.end(), [noteParenInfo](const NoteParenthesisInfo* ptr) {
1351 16 : return ptr == noteParenInfo;
1352 : });
1353 :
1354 13 : if (it != m_noteParens.end()) {
1355 13 : m_noteParens.erase(it);
1356 : }
1357 : }
1358 :
1359 9 : void Chord::addNoteToParenthesisInfo(Note* note, const Parenthesis* paren)
1360 : {
1361 9 : NoteParenthesisInfo* noteParenInfo = findNoteParenthesisInfo(paren);
1362 :
1363 9 : if (!noteParenInfo) {
1364 0 : return;
1365 : }
1366 :
1367 9 : noteParenInfo->insertNote(note);
1368 : }
1369 :
1370 12 : void Chord::removeNoteFromParenthesisInfo(Note* note, const Parenthesis* paren)
1371 : {
1372 12 : NoteParenthesisInfo* noteParenInfo = findNoteParenthesisInfo(paren);
1373 :
1374 12 : if (!noteParenInfo) {
1375 0 : return;
1376 : }
1377 :
1378 12 : noteParenInfo->removeNote(note);
1379 : }
1380 :
1381 : //---------------------------------------------------------
1382 : // isChordPlayable
1383 : // @note Now every related to chord element has it's own "PLAY" property,
1384 : // However, there is no way to control these properties outside the scope of the chord since the new Properties panel.
1385 : // So we'll use a chord as a proxy entity for "PLAY" property handling
1386 : //---------------------------------------------------------
1387 :
1388 79 : bool Chord::isChordPlayable() const
1389 : {
1390 79 : if (!m_notes.empty()) {
1391 79 : if (m_notes.front()->isPreBendOrDiveStart()) {
1392 10 : return false;
1393 : }
1394 :
1395 69 : return m_notes.front()->getProperty(Pid::PLAY).toBool();
1396 0 : } else if (tremoloTwoChord()) {
1397 0 : return tremoloTwoChord()->getProperty(Pid::PLAY).toBool();
1398 0 : } else if (tremoloSingleChord()) {
1399 0 : return tremoloSingleChord()->getProperty(Pid::PLAY).toBool();
1400 0 : } else if (m_arpeggio) {
1401 0 : return m_arpeggio->getProperty(Pid::PLAY).toBool();
1402 : }
1403 :
1404 0 : return false;
1405 : }
1406 :
1407 : //---------------------------------------------------------
1408 : // setIsChordPlayable
1409 : //---------------------------------------------------------
1410 :
1411 0 : void Chord::setIsChordPlayable(const bool isPlayable)
1412 : {
1413 0 : for (Note* note : m_notes) {
1414 0 : note->undoChangeProperty(Pid::PLAY, isPlayable);
1415 : }
1416 :
1417 0 : if (m_arpeggio) {
1418 0 : m_arpeggio->undoChangeProperty(Pid::PLAY, isPlayable);
1419 : }
1420 :
1421 0 : if (tremoloTwoChord()) {
1422 0 : tremoloTwoChord()->undoChangeProperty(Pid::PLAY, isPlayable);
1423 : }
1424 :
1425 0 : if (tremoloSingleChord()) {
1426 0 : tremoloSingleChord()->undoChangeProperty(Pid::PLAY, isPlayable);
1427 : }
1428 :
1429 0 : triggerLayout();
1430 0 : }
1431 :
1432 : //---------------------------------------------------------
1433 : // findNote
1434 : //---------------------------------------------------------
1435 :
1436 827 : Note* Chord::findNote(int pitch, int skip) const
1437 : {
1438 827 : size_t ns = m_notes.size();
1439 934 : for (size_t i = 0; i < ns; ++i) {
1440 898 : Note* n = m_notes.at(i);
1441 898 : if (n->pitch() == pitch) {
1442 791 : if (skip == 0) {
1443 791 : return n;
1444 : } else {
1445 0 : --skip;
1446 : }
1447 : }
1448 : }
1449 36 : return 0;
1450 : }
1451 :
1452 311 : void Chord::undoChangeSpanArpeggio(Arpeggio* a)
1453 : {
1454 311 : if (m_spanArpeggio == a) {
1455 230 : return;
1456 : }
1457 :
1458 : // TODO: change arpeggio for links
1459 81 : score()->undo(new ChangeSpanArpeggio(this, a));
1460 : }
1461 :
1462 14132 : ChordLine* Chord::chordLine() const
1463 : {
1464 14132 : for (EngravingItem* item : el()) {
1465 4 : if (item && item->isChordLine()) {
1466 4 : return toChordLine(item);
1467 : }
1468 : }
1469 :
1470 14128 : return nullptr;
1471 : }
1472 :
1473 : //---------------------------------------------------------
1474 : // drop
1475 : //---------------------------------------------------------
1476 :
1477 24 : EngravingItem* Chord::drop(Transaction& tx, EditData& data)
1478 : {
1479 24 : EngravingItem* e = data.dropElement;
1480 24 : switch (e->type()) {
1481 0 : case ElementType::ARTICULATION:
1482 : case ElementType::ORNAMENT:
1483 : case ElementType::TAPPING:
1484 : {
1485 0 : Articulation* atr = toArticulation(e);
1486 0 : Articulation* oa = hasArticulation(atr);
1487 0 : if (oa) {
1488 0 : delete atr;
1489 0 : atr = 0;
1490 : // if attribute is already there, remove
1491 : // score()->cmdRemove(oa); // unexpected behaviour?
1492 0 : score()->select(oa, SelectType::SINGLE, 0);
1493 : } else {
1494 : // intuit anchor for this accidental based on other accidentals in the chord
1495 0 : int aboveBelow = 0;
1496 0 : bool mixed = false;
1497 0 : for (Articulation* a : m_articulations) {
1498 0 : PropertyFlags pf = a->propertyFlags(Pid::ARTICULATION_ANCHOR);
1499 0 : if (pf == PropertyFlags::STYLED) {
1500 0 : continue;
1501 : }
1502 0 : if (a->anchor() == ArticulationAnchor::TOP) {
1503 0 : if (aboveBelow < 0) {
1504 0 : mixed = true;
1505 0 : break;
1506 : }
1507 0 : ++aboveBelow;
1508 0 : } else if (a->anchor() == ArticulationAnchor::BOTTOM) {
1509 0 : if (aboveBelow > 0) {
1510 0 : mixed = true;
1511 0 : break;
1512 : }
1513 0 : --aboveBelow;
1514 : }
1515 : }
1516 0 : if (!mixed && aboveBelow != 0) {
1517 0 : if (aboveBelow > 0) {
1518 0 : atr->setAnchor(ArticulationAnchor::TOP);
1519 : } else {
1520 0 : atr->setAnchor(ArticulationAnchor::BOTTOM);
1521 : }
1522 0 : atr->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
1523 : }
1524 0 : atr->setOwnershipParent(this);
1525 0 : atr->setTrack(track());
1526 :
1527 : // Immediately add if the chord has no existing articulations, toggle otherwise...
1528 0 : if (m_articulations.empty()) {
1529 0 : score()->undoAddElement(atr);
1530 : } else {
1531 0 : EditChord::toggleArticulation(score(), this, atr);
1532 : }
1533 : }
1534 0 : return atr;
1535 : }
1536 :
1537 3 : case ElementType::CHORDLINE:
1538 3 : e->setOwnershipParent(this);
1539 3 : e->setTrack(track());
1540 3 : score()->undoAddElement(e);
1541 3 : break;
1542 :
1543 0 : case ElementType::TREMOLO_SINGLECHORD:
1544 0 : if (tremoloSingleChord()) {
1545 0 : bool sameType = (e->subtype() == tremoloSingleChord()->subtype());
1546 0 : score()->undoRemoveElement(tremoloSingleChord());
1547 0 : if (sameType) {
1548 0 : delete e;
1549 0 : return nullptr;
1550 : }
1551 : }
1552 0 : e->setOwnershipParent(this);
1553 0 : e->setTrack(track());
1554 0 : score()->undoAddElement(e);
1555 0 : break;
1556 :
1557 0 : case ElementType::TREMOLO_TWOCHORD:
1558 : {
1559 0 : TremoloTwoChord* t = item_cast<TremoloTwoChord*>(e);
1560 0 : Segment* s = segment()->next();
1561 0 : while (s) {
1562 0 : if (s->element(track()) && s->element(track())->isChord()) {
1563 0 : break;
1564 : }
1565 0 : s = s->next();
1566 : }
1567 0 : if (s == 0) {
1568 0 : LOGD("no segment for second note of tremolo found");
1569 0 : delete e;
1570 0 : return 0;
1571 : }
1572 0 : Chord* ch2 = toChord(s->element(track()));
1573 0 : if (ch2->ticks() != ticks()) {
1574 0 : LOGD("no matching chord for second note of tremolo found");
1575 0 : delete e;
1576 0 : return 0;
1577 : }
1578 0 : t->setChords(this, ch2);
1579 : }
1580 0 : if (tremoloTwoChord()) {
1581 0 : bool sameType = (e->subtype() == tremoloTwoChord()->subtype());
1582 0 : score()->undoRemoveElement(tremoloTwoChord());
1583 0 : if (sameType) {
1584 0 : delete e;
1585 0 : return 0;
1586 : }
1587 : }
1588 0 : e->setOwnershipParent(this);
1589 0 : e->setTrack(track());
1590 0 : score()->undoAddElement(e);
1591 0 : break;
1592 :
1593 0 : case ElementType::ARPEGGIO:
1594 : case ElementType::CHORD_BRACKET:
1595 : {
1596 0 : Arpeggio* a = toArpeggio(e);
1597 0 : if (arpeggio() && a->isArpeggio()) {
1598 0 : score()->undoRemoveElement(arpeggio());
1599 : }
1600 0 : a->setTrack(track());
1601 0 : a->setOwnershipParent(this);
1602 0 : score()->undoAddElement(a);
1603 : }
1604 0 : return e;
1605 :
1606 21 : default:
1607 21 : return ChordRest::drop(tx, data);
1608 : }
1609 3 : return 0;
1610 : }
1611 :
1612 0 : void Chord::setColor(const Color& color)
1613 : {
1614 0 : ChordRest::setColor(color);
1615 :
1616 0 : for (Note* note : m_notes) {
1617 0 : note->undoChangeProperty(Pid::COLOR, PropertyValue::fromValue(color));
1618 : }
1619 0 : }
1620 :
1621 : //---------------------------------------------------------
1622 : // setStemDirection
1623 : //---------------------------------------------------------
1624 :
1625 6260 : void Chord::setStemDirection(DirectionV d)
1626 : {
1627 6260 : m_stemDirection = d;
1628 6260 : }
1629 :
1630 : //---------------------------------------------------------
1631 : // localSpatiumChanged
1632 : //---------------------------------------------------------
1633 :
1634 0 : void Chord::localSpatiumChanged(double oldValue, double newValue)
1635 : {
1636 0 : ChordRest::localSpatiumChanged(oldValue, newValue);
1637 0 : for (EngravingItem* e : graceNotes()) {
1638 0 : e->localSpatiumChanged(oldValue, newValue);
1639 : }
1640 0 : if (m_hook) {
1641 0 : m_hook->localSpatiumChanged(oldValue, newValue);
1642 : }
1643 0 : if (m_stem) {
1644 0 : m_stem->localSpatiumChanged(oldValue, newValue);
1645 : }
1646 0 : if (m_stemSlash) {
1647 0 : m_stemSlash->localSpatiumChanged(oldValue, newValue);
1648 : }
1649 0 : if (m_arpeggio) {
1650 0 : m_arpeggio->localSpatiumChanged(oldValue, newValue);
1651 : }
1652 :
1653 0 : if (m_tremoloSingleChord) {
1654 0 : m_tremoloSingleChord->localSpatiumChanged(oldValue, newValue);
1655 0 : } else if (m_tremoloTwoChord && (tremoloChordType() != TremoloChordType::TremoloSecondChord)) {
1656 0 : m_tremoloTwoChord->localSpatiumChanged(oldValue, newValue);
1657 : }
1658 :
1659 0 : for (EngravingItem* e : articulations()) {
1660 0 : e->localSpatiumChanged(oldValue, newValue);
1661 : }
1662 0 : for (Note* note : notes()) {
1663 0 : note->localSpatiumChanged(oldValue, newValue);
1664 : }
1665 0 : }
1666 :
1667 : //---------------------------------------------------------
1668 : // getProperty
1669 : //---------------------------------------------------------
1670 :
1671 302749 : PropertyValue Chord::getProperty(Pid propertyId) const
1672 : {
1673 302749 : switch (propertyId) {
1674 136 : case Pid::NO_STEM: return noStem();
1675 3 : case Pid::SHOW_STEM_SLASH: return showStemSlash();
1676 19084 : case Pid::STEM_DIRECTION: return PropertyValue::fromValue<DirectionV>(stemDirection());
1677 0 : case Pid::PLAY: return isChordPlayable();
1678 18753 : case Pid::COMBINE_VOICE: return PropertyValue::fromValue<AutoOnOff>(combineVoice());
1679 18756 : case Pid::VISIBLE: return true; // Chord cannot be set invisible, only its elements can
1680 246017 : default:
1681 246017 : return ChordRest::getProperty(propertyId);
1682 : }
1683 : }
1684 :
1685 : //---------------------------------------------------------
1686 : // propertyDefault
1687 : //---------------------------------------------------------
1688 :
1689 263616 : PropertyValue Chord::propertyDefault(Pid propertyId) const
1690 : {
1691 263616 : switch (propertyId) {
1692 0 : case Pid::NO_STEM: return false;
1693 19415 : case Pid::SHOW_STEM_SLASH: return noteType() == NoteType::ACCIACCATURA;
1694 37506 : case Pid::STEM_DIRECTION: return PropertyValue::fromValue<DirectionV>(DirectionV::AUTO);
1695 0 : case Pid::PLAY: return true;
1696 37506 : case Pid::COMBINE_VOICE: return AutoOnOff::AUTO;
1697 206695 : default:
1698 206695 : return ChordRest::propertyDefault(propertyId);
1699 : }
1700 : }
1701 :
1702 0 : bool Chord::isUserModified() const
1703 : {
1704 0 : if (showStemSlash() != propertyDefault(Pid::SHOW_STEM_SLASH).toBool()) {
1705 0 : return true;
1706 : }
1707 :
1708 0 : return EngravingItem::isUserModified();
1709 : }
1710 :
1711 : //---------------------------------------------------------
1712 : // setProperty
1713 : //---------------------------------------------------------
1714 :
1715 2184 : bool Chord::setProperty(Pid propertyId, const PropertyValue& v)
1716 : {
1717 2184 : switch (propertyId) {
1718 64 : case Pid::NO_STEM:
1719 64 : setNoStem(v.toBool());
1720 64 : break;
1721 663 : case Pid::SHOW_STEM_SLASH:
1722 663 : requestShowStemSlash(v.toBool());
1723 663 : break;
1724 675 : case Pid::STEM_DIRECTION:
1725 675 : setStemDirection(v.value<DirectionV>());
1726 675 : break;
1727 0 : case Pid::PLAY:
1728 0 : setIsChordPlayable(v.toBool());
1729 0 : break;
1730 0 : case Pid::COMBINE_VOICE:
1731 0 : setCombineVoice(v.value<AutoOnOff>());
1732 0 : break;
1733 782 : default:
1734 782 : return ChordRest::setProperty(propertyId, v);
1735 : }
1736 1402 : triggerLayout();
1737 1402 : return true;
1738 : }
1739 :
1740 : //---------------------------------------------------------
1741 : // hasArticulation
1742 : //---------------------------------------------------------
1743 :
1744 313 : Articulation* Chord::hasArticulation(const Articulation* aa)
1745 : {
1746 462 : for (Articulation* a : m_articulations) {
1747 160 : if (a->subtype() == aa->subtype()) {
1748 11 : return a;
1749 : }
1750 : }
1751 302 : return 0;
1752 : }
1753 :
1754 1163 : Tapping* Chord::tapping() const
1755 : {
1756 1163 : std::vector<Tapping*> tappings;
1757 1163 : tappings.reserve(1);
1758 1177 : for (Articulation* a : m_articulations) {
1759 14 : if (a->isTapping()) {
1760 0 : tappings.push_back(toTapping(a));
1761 : }
1762 : }
1763 1163 : DO_ASSERT(tappings.size() <= 1);
1764 :
1765 2326 : return tappings.size() > 0 ? tappings.front() : nullptr;
1766 1163 : }
1767 :
1768 18 : void Chord::updateArticulations(const std::set<SymId>& newArticulationIds, ArticulationsUpdateMode updateMode)
1769 : {
1770 18 : Articulation* staccato = nullptr;
1771 18 : Articulation* accent = nullptr;
1772 18 : Articulation* marcato = nullptr;
1773 18 : Articulation* tenuto = nullptr;
1774 18 : ArticulationAnchor overallAnchor = ArticulationAnchor::AUTO;
1775 18 : bool mixedDirections = false;
1776 18 : if (!m_articulations.empty()) {
1777 0 : std::vector<Articulation*> articsToRemove;
1778 : // split all articulations
1779 0 : for (Articulation* artic : m_articulations) {
1780 0 : if (!artic->isDouble()) {
1781 0 : continue;
1782 : }
1783 0 : auto splitSyms = splitArticulations({ artic->symId() });
1784 0 : for (const SymId& id : splitSyms) {
1785 0 : Articulation* newArticulation = Factory::createArticulation(this);
1786 0 : newArticulation->setSymId(id);
1787 0 : newArticulation->setAnchor(artic->anchor());
1788 0 : newArticulation->setPropertyFlags(Pid::ARTICULATION_ANCHOR, artic->propertyFlags(Pid::ARTICULATION_ANCHOR));
1789 0 : if (!hasArticulation(newArticulation)) {
1790 0 : EditChord::toggleArticulation(score(), this, newArticulation);
1791 : } else {
1792 0 : delete newArticulation;
1793 : }
1794 : }
1795 0 : articsToRemove.push_back(artic);
1796 0 : }
1797 0 : for (Articulation* artic : articsToRemove) {
1798 0 : score()->undoRemoveElement(artic);
1799 : }
1800 : // now we have guaranteed no more combined artics
1801 : // take an inventory of which articulations are already present
1802 0 : for (Articulation* artic : m_articulations) {
1803 0 : PropertyFlags pf = artic->propertyFlags(Pid::ARTICULATION_ANCHOR);
1804 0 : if (!mixedDirections && pf == PropertyFlags::UNSTYLED && artic->anchor() != ArticulationAnchor::AUTO) {
1805 0 : if (overallAnchor != ArticulationAnchor::AUTO && artic->anchor() != overallAnchor) {
1806 0 : mixedDirections = true;
1807 0 : overallAnchor = ArticulationAnchor::AUTO;
1808 : } else {
1809 0 : overallAnchor = artic->anchor();
1810 : }
1811 : }
1812 0 : if (artic->isStaccato()) {
1813 0 : staccato = artic;
1814 0 : } else if (artic->isAccent()) {
1815 0 : accent = artic;
1816 0 : } else if (artic->isMarcato()) {
1817 0 : marcato = artic;
1818 0 : } else if (artic->isTenuto()) {
1819 0 : tenuto = artic;
1820 : }
1821 : }
1822 0 : }
1823 18 : std::set<SymId> newArtics;
1824 : // get symbol id's for correct direction
1825 18 : for (const SymId& id : newArticulationIds) {
1826 0 : if (id == SymId::articAccentAbove || id == SymId::articAccentBelow) {
1827 0 : if (marcato && updateMode == ArticulationsUpdateMode::Insert) {
1828 : // adding an accent, which replaces marcato
1829 0 : score()->undoRemoveElement(marcato);
1830 : }
1831 0 : } else if (id == SymId::articMarcatoAbove || id == SymId::articMarcatoBelow) {
1832 0 : if (accent && updateMode == ArticulationsUpdateMode::Insert) {
1833 : // adding a marcato, which replaces accent
1834 0 : score()->undoRemoveElement(accent);
1835 : }
1836 : }
1837 0 : newArtics.insert(id);
1838 : }
1839 :
1840 : // newArtics now contains the articulations in the correct direction
1841 18 : if (updateMode == ArticulationsUpdateMode::Remove) {
1842 : // remove articulations from _articulations that are found in newArtics
1843 0 : for (const SymId& id : newArtics) {
1844 0 : switch (id) {
1845 0 : case SymId::articAccentAbove:
1846 : case SymId::articAccentBelow:
1847 0 : score()->undoRemoveElement(accent);
1848 0 : accent = nullptr;
1849 0 : break;
1850 0 : case SymId::articMarcatoAbove:
1851 : case SymId::articMarcatoBelow:
1852 0 : score()->undoRemoveElement(marcato);
1853 0 : marcato = nullptr;
1854 0 : break;
1855 0 : case SymId::articTenutoAbove:
1856 : case SymId::articTenutoBelow:
1857 0 : score()->undoRemoveElement(tenuto);
1858 0 : tenuto = nullptr;
1859 0 : break;
1860 0 : case SymId::articStaccatoAbove:
1861 : case SymId::articStaccatoBelow:
1862 0 : score()->undoRemoveElement(staccato);
1863 0 : staccato = nullptr;
1864 0 : break;
1865 0 : default:
1866 0 : break;
1867 : }
1868 : }
1869 : } else {
1870 : // add articulations from newArtics that are not found in m_articulations
1871 18 : for (const SymId& id : newArtics) {
1872 0 : Articulation* newArticulation = Factory::createArticulation(this);
1873 0 : newArticulation->setSymId(id);
1874 0 : if (overallAnchor != ArticulationAnchor::AUTO) {
1875 0 : newArticulation->setAnchor(overallAnchor);
1876 0 : newArticulation->setPropertyFlags(Pid::ARTICULATION_ANCHOR, PropertyFlags::UNSTYLED);
1877 : }
1878 0 : if (!hasArticulation(newArticulation)) {
1879 0 : EditChord::toggleArticulation(score(), this, newArticulation);
1880 : } else {
1881 0 : delete newArticulation;
1882 : }
1883 : }
1884 : }
1885 18 : }
1886 :
1887 : //---------------------------------------------------------
1888 : // reset
1889 : //---------------------------------------------------------
1890 :
1891 0 : void Chord::reset()
1892 : {
1893 0 : undoChangeProperty(Pid::STEM_DIRECTION, DirectionV::AUTO);
1894 0 : ChordRest::reset();
1895 0 : }
1896 :
1897 : //---------------------------------------------------------
1898 : // slash
1899 : //---------------------------------------------------------
1900 :
1901 2223 : bool Chord::slash()
1902 : {
1903 2223 : Note* n = upNote();
1904 2223 : return n->fixed();
1905 : }
1906 :
1907 : //---------------------------------------------------------
1908 : // setSlash
1909 : //---------------------------------------------------------
1910 :
1911 90 : void Chord::setSlash(bool flag, bool stemless)
1912 : {
1913 90 : int line = 0;
1914 90 : NoteHeadGroup head = NoteHeadGroup::HEAD_SLASH;
1915 :
1916 90 : if (!flag) {
1917 : // restore to normal
1918 0 : undoChangeProperty(Pid::NO_STEM, false);
1919 0 : undoChangeProperty(Pid::SMALL, false);
1920 0 : undoChangeProperty(Pid::OFFSET, PointF());
1921 0 : for (Note* n : m_notes) {
1922 0 : n->undoChangeProperty(Pid::HEAD_GROUP, NoteHeadGroup::HEAD_NORMAL);
1923 0 : n->undoChangeProperty(Pid::FIXED, false);
1924 0 : n->undoChangeProperty(Pid::FIXED_LINE, 0);
1925 0 : n->undoChangeProperty(Pid::PLAY, true);
1926 0 : n->undoChangeProperty(Pid::VISIBLE, true);
1927 0 : for (NoteDot* dot : n->dots()) {
1928 0 : dot->undoChangeProperty(Pid::VISIBLE, true);
1929 : }
1930 0 : if (staff()->isDrumStaff(tick())) {
1931 0 : const Drumset* ds = originPart()->instrument(tick())->drumset();
1932 0 : int pitch = n->pitch();
1933 0 : if (ds && ds->isValid(pitch)) {
1934 0 : undoChangeProperty(Pid::STEM_DIRECTION, ds->stemDirection(pitch));
1935 0 : n->undoChangeProperty(Pid::HEAD_GROUP, ds->noteHead(pitch));
1936 : }
1937 : }
1938 : }
1939 0 : return;
1940 : }
1941 :
1942 : // make stemless if asked
1943 90 : if (stemless) {
1944 36 : undoChangeProperty(Pid::NO_STEM, true);
1945 36 : undoChangeProperty(Pid::BEAM_MODE, BeamMode::NONE);
1946 : }
1947 :
1948 90 : const StaffType* staffType = this->staffType();
1949 :
1950 : // voice-dependent attributes - line, size, offset, head
1951 90 : if (track() % VOICES < 2) {
1952 : // use middle line
1953 64 : line = staffType->middleLine();
1954 64 : undoChangeProperty(Pid::STEM_DIRECTION, PropertyValue::fromValue<DirectionV>(DirectionV::DOWN));
1955 : } else {
1956 : // set small
1957 26 : undoChangeProperty(Pid::SMALL, true);
1958 : // set outside the staff
1959 26 : double y = 0.0;
1960 26 : if (track() % 2) {
1961 12 : line = staffType->bottomLine() + 1;
1962 12 : y = 0.5 * spatium();
1963 12 : undoChangeProperty(Pid::STEM_DIRECTION, PropertyValue::fromValue<DirectionV>(DirectionV::DOWN));
1964 : } else {
1965 14 : line = -1;
1966 14 : if (!staffType->isDrumStaff()) {
1967 9 : y = -0.5 * spatium();
1968 : }
1969 14 : undoChangeProperty(Pid::STEM_DIRECTION, PropertyValue::fromValue<DirectionV>(DirectionV::UP));
1970 : }
1971 : // for non-drum staves, add an additional offset
1972 : // for drum staves, no offset, but use normal head
1973 26 : if (!staffType->isDrumStaff()) {
1974 15 : mutldata()->moveY(y);
1975 : } else {
1976 11 : head = NoteHeadGroup::HEAD_NORMAL;
1977 : }
1978 : }
1979 :
1980 90 : size_t ns = m_notes.size();
1981 180 : for (size_t i = 0; i < ns; ++i) {
1982 90 : Note* n = m_notes[i];
1983 90 : n->undoChangeProperty(Pid::HEAD_GROUP, head);
1984 90 : n->undoChangeProperty(Pid::FIXED, true);
1985 90 : n->undoChangeProperty(Pid::FIXED_LINE, line);
1986 90 : n->undoChangeProperty(Pid::PLAY, false);
1987 : // hide all but first notehead
1988 90 : if (i) {
1989 0 : n->undoChangeProperty(Pid::VISIBLE, false);
1990 0 : for (NoteDot* dot : n->dots()) {
1991 0 : dot->undoChangeProperty(Pid::VISIBLE, false);
1992 : }
1993 : }
1994 : }
1995 : }
1996 :
1997 : //---------------------------------------------------------
1998 : // updateEndsNoteAnchoredLine
1999 : // sets/resets the chord m_endsNoteAnchoredLine according any note anchored line
2000 : // end into this chord or no.
2001 : //---------------------------------------------------------
2002 :
2003 0 : void Chord::updateEndsNoteAnchoredLine()
2004 : {
2005 0 : m_endsNoteAnchoredLine = false; // assume no note anchored line ends here
2006 : // scan all chord notes for note anchored lines ending on this chord
2007 0 : for (Note* note : notes()) {
2008 0 : for (Spanner* sp : note->spannerBack()) {
2009 0 : if (sp->isGlissando() || (sp->isNoteLine() && toNoteLine(sp)->enforceMinLength())) {
2010 0 : m_endsNoteAnchoredLine = true;
2011 0 : return;
2012 : }
2013 : }
2014 : }
2015 : }
2016 :
2017 : //---------------------------------------------------------
2018 : // removeMarkings
2019 : // - this is normally called after cloning a chord to tie a note over the barline
2020 : // - there is no special undo handling; the assumption is that undo will simply remove the cloned chord
2021 : // - two note tremolos are converted into simple notes
2022 : // - single note tremolos are optionally retained
2023 : //---------------------------------------------------------
2024 :
2025 122 : void Chord::removeMarkings(bool keepTremolo)
2026 : {
2027 122 : if (m_tremoloSingleChord && !keepTremolo) {
2028 0 : remove(m_tremoloSingleChord);
2029 : }
2030 :
2031 122 : if (m_tremoloTwoChord && !keepTremolo) {
2032 0 : remove(m_tremoloTwoChord);
2033 : }
2034 :
2035 122 : if (arpeggio()) {
2036 0 : remove(arpeggio());
2037 : }
2038 :
2039 122 : if (m_spanArpeggio) {
2040 0 : m_spanArpeggio = nullptr;
2041 : }
2042 :
2043 122 : muse::DeleteAll(graceNotes());
2044 122 : graceNotes().clear();
2045 122 : muse::DeleteAll(articulations());
2046 122 : articulations().clear();
2047 246 : for (Note* n : notes()) {
2048 124 : for (EngravingItem* e : n->el()) {
2049 0 : n->remove(e);
2050 : }
2051 : }
2052 122 : ChordRest::removeMarkings(keepTremolo);
2053 122 : }
2054 :
2055 : //---------------------------------------------------------
2056 : // intrinsicMag
2057 : // returns the INTRINSIC mag of the chord (i.e. NOT scaled
2058 : // by staff size)
2059 : //---------------------------------------------------------
2060 :
2061 5411939 : double Chord::intrinsicMag() const
2062 : {
2063 5411939 : double m = 1.0;
2064 5411939 : if (isSmall()) {
2065 42108 : m *= style().styleD(Sid::smallNoteMag);
2066 : }
2067 5411939 : if (m_noteType != NoteType::NORMAL) {
2068 160397 : bool tabGraceSizeException = staffType()->isTabStaff() && isPreBendOrGraceBendStart()
2069 160397 : && !style().styleB(Sid::useCueSizeFretForGraceBends);
2070 159400 : if (!tabGraceSizeException) {
2071 159109 : m *= style().styleD(Sid::graceNoteMag);
2072 : }
2073 : }
2074 5411939 : return m;
2075 : }
2076 :
2077 : //---------------------------------------------------------
2078 : // mag
2079 : //---------------------------------------------------------
2080 :
2081 4480676 : double Chord::mag() const
2082 : {
2083 4480676 : const Staff* st = staff();
2084 4480676 : return (st ? st->staffMag(this) : 1.0) * intrinsicMag();
2085 : }
2086 :
2087 : //---------------------------------------------------------
2088 : // segment
2089 : //---------------------------------------------------------
2090 :
2091 630877 : Segment* Chord::segment() const
2092 : {
2093 630877 : EngravingObject* e = ownershipParent();
2094 638564 : for (; e && !e->isSegment(); e = e->ownershipParent()) {
2095 : }
2096 630877 : return toSegment(e);
2097 : }
2098 :
2099 : //---------------------------------------------------------
2100 : // measure
2101 : //---------------------------------------------------------
2102 :
2103 5512670 : Measure* Chord::measure() const
2104 : {
2105 5512670 : EngravingObject* e = ownershipParent();
2106 11126460 : for (; e && !e->isMeasure(); e = e->ownershipParent()) {
2107 : }
2108 5512670 : return toMeasure(e);
2109 : }
2110 :
2111 : //---------------------------------------------------------
2112 : // graceNotesBefore
2113 : //---------------------------------------------------------
2114 :
2115 308575 : GraceNotesGroup& Chord::graceNotesBefore(bool filterUnplayable) const
2116 : {
2117 308575 : m_graceNotesBefore.clear();
2118 316789 : for (Chord* c : m_graceNotes) {
2119 8214 : assert(c->noteType() != NoteType::NORMAL && c->noteType() != NoteType::INVALID);
2120 8214 : if (c->noteType() & (
2121 : NoteType::ACCIACCATURA
2122 : | NoteType::APPOGGIATURA
2123 : | NoteType::GRACE4
2124 : | NoteType::GRACE16
2125 : | NoteType::GRACE32)) {
2126 6117 : if (filterUnplayable && !c->isChordPlayable()) {
2127 9 : continue;
2128 : }
2129 :
2130 6108 : m_graceNotesBefore.push_back(c);
2131 : }
2132 : }
2133 308575 : return m_graceNotesBefore;
2134 : }
2135 :
2136 : //---------------------------------------------------------
2137 : // graceNotesAfter
2138 : //---------------------------------------------------------
2139 :
2140 307663 : GraceNotesGroup& Chord::graceNotesAfter(bool filterUnplayable) const
2141 : {
2142 307663 : m_graceNotesAfter.clear();
2143 315193 : for (int i = static_cast<int>(m_graceNotes.size()) - 1; i >= 0; i--) {
2144 7530 : Chord* c = m_graceNotes[i];
2145 7530 : assert(c->noteType() != NoteType::NORMAL && c->noteType() != NoteType::INVALID);
2146 7530 : if (c->noteType() & (NoteType::GRACE8_AFTER | NoteType::GRACE16_AFTER | NoteType::GRACE32_AFTER)) {
2147 1968 : if (filterUnplayable && !c->isChordPlayable()) {
2148 0 : continue;
2149 : }
2150 :
2151 1968 : m_graceNotesAfter.push_back(c);
2152 : }
2153 : }
2154 307663 : return m_graceNotesAfter;
2155 : }
2156 :
2157 22 : Chord* Chord::graceNoteAt(size_t idx) const
2158 : {
2159 22 : if (idx > m_graceNotes.size()) {
2160 0 : return nullptr;
2161 : }
2162 :
2163 22 : return m_graceNotes.at(idx);
2164 : }
2165 :
2166 : //---------------------------------------------------------
2167 : // allGraceChordsOfMainChord
2168 : // returns a list containing all grace notes (chords) attached to the main chord and the main chord itself, in order
2169 : //---------------------------------------------------------
2170 0 : std::vector<Chord*> Chord::allGraceChordsOfMainChord()
2171 : {
2172 0 : Chord* mainChord = isGrace() ? toChord(ownershipParent()) : this;
2173 0 : std::vector<Chord*> chords = { mainChord };
2174 0 : const GraceNotesGroup& gnBefore = mainChord->graceNotesBefore();
2175 0 : const GraceNotesGroup& gnAfter = mainChord->graceNotesAfter();
2176 0 : chords.insert(chords.begin(), gnBefore.begin(), gnBefore.end());
2177 0 : chords.insert(chords.end(), gnAfter.begin(), gnAfter.end());
2178 0 : return chords;
2179 0 : }
2180 :
2181 : //---------------------------------------------------------
2182 : // setShowStemSlashInAdvance
2183 : //---------------------------------------------------------
2184 :
2185 70 : void Chord::setShowStemSlashInAdvance()
2186 : {
2187 70 : if (m_noteType == NoteType::NORMAL) {
2188 0 : return;
2189 : }
2190 70 : if (isGraceBefore()) {
2191 69 : GraceNotesGroup& graceBefore = toChord(ownershipParent())->graceNotesBefore();
2192 69 : Chord* grace = graceBefore.empty() ? nullptr : graceBefore.front();
2193 69 : if (grace && grace->beamMode() != BeamMode::NONE && grace->beamMode() != BeamMode::BEGIN) {
2194 2 : grace->requestShowStemSlash(showStemSlash());
2195 : }
2196 : }
2197 70 : if (isGraceAfter()) {
2198 1 : GraceNotesGroup& graceAfter = toChord(ownershipParent())->graceNotesAfter();
2199 1 : Chord* grace = graceAfter.empty() ? nullptr : graceAfter.back();
2200 1 : if (grace && grace->beamMode() != BeamMode::NONE) {
2201 0 : grace->requestShowStemSlash(showStemSlash());
2202 : }
2203 : }
2204 : }
2205 :
2206 : //---------------------------------------------------------
2207 : // requestShowStemSlash
2208 : //---------------------------------------------------------
2209 :
2210 665 : void Chord::requestShowStemSlash(bool show)
2211 : {
2212 665 : if (m_noteType == NoteType::NORMAL) {
2213 2 : return;
2214 : }
2215 663 : if (beam()) {
2216 0 : for (ChordRest* chordRest : beam()->elements()) {
2217 0 : if (chordRest->isChord()) {
2218 0 : Chord* chord = toChord(chordRest);
2219 0 : chord->setShowStemSlash(show);
2220 : }
2221 : }
2222 : } else {
2223 663 : setShowStemSlash(show);
2224 : }
2225 : }
2226 :
2227 : //---------------------------------------------------------
2228 : // sortNotes
2229 : //---------------------------------------------------------
2230 :
2231 50325 : void Chord::sortNotes()
2232 : {
2233 50325 : std::sort(notes().begin(), notes().end(), noteIsBefore);
2234 50325 : }
2235 :
2236 : //---------------------------------------------------------
2237 : // nextTiedChord
2238 : // Return next chord if all notes in this chord are tied to it.
2239 : // Set backwards=true to return the previous chord instead.
2240 : //
2241 : // Note: the next chord might have extra notes that are not tied
2242 : // back to this one. Set sameSize=true to return 0 in this case.
2243 : //---------------------------------------------------------
2244 :
2245 1776 : Chord* Chord::nextTiedChord(bool backwards, bool sameSize) const
2246 : {
2247 1776 : Segment* nextSeg = backwards ? segment()->prev1(SegmentType::ChordRest) : segment()->next1(SegmentType::ChordRest);
2248 1776 : if (!nextSeg) {
2249 91 : return 0;
2250 : }
2251 1685 : ChordRest* nextCR = nextSeg->nextChordRest(track(), backwards);
2252 1685 : if (!nextCR || !nextCR->isChord()) {
2253 428 : return 0;
2254 : }
2255 1257 : Chord* next = toChord(nextCR);
2256 1257 : if (sameSize && notes().size() != next->notes().size()) {
2257 6 : return 0; // sizes don't match so some notes can't be tied
2258 : }
2259 1251 : if (tuplet() != next->tuplet()) {
2260 2 : return 0; // next chord belongs to a different tuplet
2261 : }
2262 2055 : for (Note* n : m_notes) {
2263 1260 : Tie* tie = backwards ? n->tieBack() : n->tieFor();
2264 1260 : if (!tie) {
2265 454 : return 0; // not tied
2266 : }
2267 806 : Note* nn = backwards ? tie->startNote() : tie->endNote();
2268 806 : if (!nn || nn->chord() != next) {
2269 0 : return 0; // tied to note in wrong voice, or tied over rest
2270 : }
2271 : }
2272 795 : return next; // all notes in this chord are tied to notes in next chord
2273 : }
2274 :
2275 : //---------------------------------------------------------
2276 : // setNoteType
2277 : //---------------------------------------------------------
2278 :
2279 662 : void Chord::setNoteType(NoteType t)
2280 : {
2281 662 : m_noteType = t;
2282 662 : setProperty(Pid::SHOW_STEM_SLASH, propertyDefault(Pid::SHOW_STEM_SLASH));
2283 662 : }
2284 :
2285 : //---------------------------------------------------------
2286 : // toGraceAfter
2287 : //---------------------------------------------------------
2288 :
2289 13 : void Chord::toGraceAfter()
2290 : {
2291 13 : switch (noteType()) {
2292 13 : case NoteType::APPOGGIATURA: setNoteType(NoteType::GRACE8_AFTER);
2293 13 : break;
2294 0 : case NoteType::GRACE16: setNoteType(NoteType::GRACE16_AFTER);
2295 0 : break;
2296 0 : case NoteType::GRACE32: setNoteType(NoteType::GRACE32_AFTER);
2297 0 : break;
2298 0 : default: break;
2299 : }
2300 13 : }
2301 :
2302 997 : bool Chord::isPreBendOrGraceBendStart() const
2303 : {
2304 997 : if (!isGrace()) {
2305 0 : return false;
2306 : }
2307 :
2308 1703 : for (const Note* note : m_notes) {
2309 997 : GuitarBend* gb = note->bendFor();
2310 997 : if (gb && (gb->bendType() == GuitarBendType::PRE_BEND || gb->bendType() == GuitarBendType::GRACE_NOTE_BEND
2311 0 : || gb->bendType() == GuitarBendType::PRE_DIVE)) {
2312 291 : return true;
2313 : }
2314 : }
2315 :
2316 706 : return false;
2317 : }
2318 :
2319 413 : bool Chord::isGraceBendEnd() const
2320 : {
2321 413 : if (isGrace() || m_graceNotes.empty()) {
2322 400 : return false;
2323 : }
2324 :
2325 22 : for (const Note* note : m_notes) {
2326 13 : GuitarBend* bendBack = note->bendBack();
2327 13 : if (bendBack && bendBack->bendType() == GuitarBendType::GRACE_NOTE_BEND) {
2328 4 : return true;
2329 : }
2330 : }
2331 :
2332 9 : return false;
2333 : }
2334 :
2335 18 : void Chord::setIsTrillCueNote(bool v)
2336 : {
2337 18 : m_isTrillCueNote = v;
2338 18 : }
2339 :
2340 : //---------------------------------------------------------
2341 : // tremoloChordType
2342 : //---------------------------------------------------------
2343 :
2344 7869 : TremoloChordType Chord::tremoloChordType() const
2345 : {
2346 7869 : if (m_tremoloTwoChord) {
2347 260 : if (m_tremoloTwoChord->chord1() == this) {
2348 127 : return TremoloChordType::TremoloFirstChord;
2349 133 : } else if (m_tremoloTwoChord->chord2() == this) {
2350 133 : return TremoloChordType::TremoloSecondChord;
2351 : } else {
2352 0 : ASSERT_X(String(u"Chord::tremoloChordType(): inconsistency"));
2353 : }
2354 7609 : } else if (m_tremoloSingleChord) {
2355 134 : return TremoloChordType::TremoloSingle;
2356 : }
2357 :
2358 7475 : return TremoloChordType::TremoloNone;
2359 : }
2360 :
2361 : //---------------------------------------------------------
2362 : // nextElement
2363 : //---------------------------------------------------------
2364 :
2365 0 : EngravingItem* Chord::nextElement()
2366 : {
2367 0 : EngravingItem* e = score()->selection().element();
2368 0 : if (!e && !score()->selection().elements().empty()) {
2369 0 : e = score()->selection().elements().front();
2370 : }
2371 :
2372 0 : switch (e->type()) {
2373 0 : case ElementType::SYMBOL:
2374 : case ElementType::IMAGE:
2375 : case ElementType::FINGERING:
2376 : case ElementType::TEXT:
2377 : case ElementType::BEND: {
2378 0 : Note* n = toNote(e->ownershipParent());
2379 0 : if (n == m_notes.front()) {
2380 0 : if (m_arpeggio) {
2381 0 : return m_arpeggio;
2382 0 : } else if (m_tremoloTwoChord) {
2383 0 : return m_tremoloTwoChord;
2384 0 : } else if (m_tremoloSingleChord) {
2385 0 : return m_tremoloSingleChord;
2386 : }
2387 0 : break;
2388 : }
2389 0 : for (auto& i : m_notes) {
2390 0 : if (i == n) {
2391 0 : return *(&i - 1);
2392 : }
2393 : }
2394 0 : break;
2395 : }
2396 :
2397 0 : case ElementType::GUITAR_BEND_SEGMENT:
2398 : case ElementType::GLISSANDO_SEGMENT:
2399 : case ElementType::NOTELINE_SEGMENT:
2400 : case ElementType::LAISSEZ_VIB_SEGMENT:
2401 : case ElementType::PARTIAL_TIE_SEGMENT:
2402 : case ElementType::TIE_SEGMENT: {
2403 0 : SpannerSegment* s = toSpannerSegment(e);
2404 0 : Spanner* sp = s->spanner();
2405 0 : EngravingItem* elSt = sp->startElement();
2406 0 : assert(elSt->isNote());
2407 0 : Note* n = toNote(elSt);
2408 0 : assert(n != NULL);
2409 0 : if (n == m_notes.front()) {
2410 0 : if (m_arpeggio) {
2411 0 : return m_arpeggio;
2412 0 : } else if (m_tremoloTwoChord) {
2413 0 : return m_tremoloTwoChord;
2414 0 : } else if (m_tremoloSingleChord) {
2415 0 : return m_tremoloSingleChord;
2416 : }
2417 0 : break;
2418 : }
2419 0 : for (auto& i : m_notes) {
2420 0 : if (i == n) {
2421 0 : return *(&i - 1);
2422 : }
2423 : }
2424 0 : break;
2425 : }
2426 0 : case ElementType::ARPEGGIO:
2427 : case ElementType::CHORD_BRACKET:
2428 0 : if (m_tremoloTwoChord) {
2429 0 : return m_tremoloTwoChord;
2430 0 : } else if (m_tremoloSingleChord) {
2431 0 : return m_tremoloSingleChord;
2432 : }
2433 0 : break;
2434 :
2435 0 : case ElementType::ACCIDENTAL:
2436 0 : e = toAccidental(e)->note();
2437 : // fall through
2438 :
2439 0 : case ElementType::NOTE: {
2440 0 : if (e == m_notes.front()) {
2441 0 : if (m_arpeggio) {
2442 0 : return m_arpeggio;
2443 0 : } else if (m_tremoloTwoChord) {
2444 0 : return m_tremoloTwoChord;
2445 0 : } else if (m_tremoloSingleChord) {
2446 0 : return m_tremoloSingleChord;
2447 : }
2448 0 : break;
2449 : }
2450 0 : for (auto& i : m_notes) {
2451 0 : if (i == e) {
2452 0 : return *(&i - 1);
2453 : }
2454 : }
2455 : }
2456 0 : break;
2457 :
2458 0 : case ElementType::CHORD:
2459 0 : return m_notes.back();
2460 :
2461 0 : default:
2462 0 : break;
2463 : }
2464 :
2465 0 : return ChordRest::nextElement();
2466 : }
2467 :
2468 : //---------------------------------------------------------
2469 : // prevElement
2470 : //---------------------------------------------------------
2471 :
2472 0 : EngravingItem* Chord::prevElement()
2473 : {
2474 0 : EngravingItem* e = score()->selection().element();
2475 0 : if (!e && !score()->selection().elements().empty()) {
2476 0 : e = score()->selection().elements().back();
2477 : }
2478 0 : switch (e->type()) {
2479 0 : case ElementType::NOTE: {
2480 0 : if (isGrace()) {
2481 0 : ChordRest* prev = Navigation::prevChordRest(this);
2482 0 : if (prev) {
2483 0 : if (prev->isChord()) {
2484 0 : return toChord(prev)->notes().back();
2485 : }
2486 0 : return prev;
2487 : }
2488 : }
2489 :
2490 0 : GraceNotesGroup& graceNotesBefore = this->graceNotesBefore();
2491 0 : if (!graceNotesBefore.empty()) {
2492 0 : if (Chord* graceNotesBeforeLastChord = graceNotesBefore.back()) {
2493 0 : if (e == graceNotesBeforeLastChord->notes().back()) {
2494 0 : break;
2495 : }
2496 :
2497 0 : Note* prevNote = graceNotesBeforeLastChord->notes().back();
2498 0 : if (prevNote->isPreBendOrDiveStart() || prevNote->isGraceBendStart()) {
2499 0 : return prevNote->bendFor()->frontSegment();
2500 : }
2501 :
2502 0 : ChordRest* prev = Navigation::prevChordRest(this);
2503 0 : if (prev) {
2504 0 : if (prev->isChord()) {
2505 0 : return toChord(prev)->notes().back();
2506 : }
2507 0 : return prev;
2508 : }
2509 : }
2510 : }
2511 :
2512 0 : if (e == m_notes.back()) {
2513 0 : break;
2514 : }
2515 0 : Note* prevNote = nullptr;
2516 0 : for (auto& i : m_notes) {
2517 0 : if (i == e) {
2518 0 : prevNote = *(&i + 1);
2519 : }
2520 : }
2521 0 : EngravingItem* next = prevNote->lastElementBeforeSegment();
2522 0 : return next;
2523 : }
2524 :
2525 0 : case ElementType::CHORD:
2526 0 : return m_notes.front();
2527 :
2528 0 : case ElementType::TREMOLO_TWOCHORD:
2529 : case ElementType::TREMOLO_SINGLECHORD:
2530 0 : if (m_arpeggio) {
2531 0 : return m_arpeggio;
2532 : }
2533 : // fall through
2534 : case ElementType::ARPEGGIO:
2535 : case ElementType::CHORD_BRACKET:
2536 : {
2537 0 : Note* n = m_notes.front();
2538 0 : EngravingItem* elN = n->lastElementBeforeSegment();
2539 0 : assert(elN != NULL);
2540 0 : return elN;
2541 : }
2542 :
2543 0 : default:
2544 0 : break;
2545 : }
2546 0 : return ChordRest::prevElement();
2547 : }
2548 :
2549 : //---------------------------------------------------------
2550 : // lastElementBeforeSegment
2551 : //---------------------------------------------------------
2552 :
2553 0 : EngravingItem* Chord::lastElementBeforeSegment()
2554 : {
2555 0 : if (m_tremoloSingleChord) {
2556 0 : return m_tremoloSingleChord;
2557 0 : } else if (m_tremoloTwoChord) {
2558 0 : return m_tremoloTwoChord;
2559 0 : } else if (m_arpeggio) {
2560 0 : return m_arpeggio;
2561 : } else {
2562 0 : Note* n = m_notes.front();
2563 0 : EngravingItem* elN = n->lastElementBeforeSegment();
2564 0 : assert(elN != NULL);
2565 0 : return elN;
2566 : }
2567 : }
2568 :
2569 : //---------------------------------------------------------
2570 : // nextSegmentElement
2571 : //---------------------------------------------------------
2572 :
2573 0 : EngravingItem* Chord::nextSegmentElement()
2574 : {
2575 0 : for (track_idx_t v = track() + 1; staffIdx() == v / VOICES; ++v) {
2576 0 : EngravingItem* e = segment()->element(v);
2577 0 : if (e) {
2578 0 : if (e->isChord()) {
2579 0 : return toChord(e)->notes().back();
2580 : }
2581 :
2582 0 : return e;
2583 : }
2584 : }
2585 :
2586 0 : return ChordRest::nextSegmentElement();
2587 : }
2588 :
2589 : //---------------------------------------------------------
2590 : // prevSegmentElement
2591 : //---------------------------------------------------------
2592 :
2593 0 : EngravingItem* Chord::prevSegmentElement()
2594 : {
2595 0 : EngravingItem* el = score()->selection().element();
2596 0 : if (!el && !score()->selection().elements().empty()) {
2597 0 : el = score()->selection().elements().front();
2598 : }
2599 0 : EngravingItem* e = segment()->lastInPrevSegments(el->staffIdx());
2600 0 : if (e) {
2601 0 : if (e->isChord()) {
2602 0 : return toChord(e)->notes().front();
2603 : }
2604 0 : return e;
2605 : }
2606 :
2607 0 : return ChordRest::prevSegmentElement();
2608 : }
2609 :
2610 : //---------------------------------------------------------
2611 : // accessibleExtraInfo
2612 : //---------------------------------------------------------
2613 :
2614 0 : String Chord::accessibleExtraInfo() const
2615 : {
2616 0 : String rez;
2617 :
2618 0 : for (const Chord* c : graceNotes()) {
2619 0 : if (!score()->selectionFilter().canSelect(c)) {
2620 0 : continue;
2621 : }
2622 0 : for (const Note* n : c->notes()) {
2623 0 : rez = String(u"%1 %2").arg(rez, n->screenReaderInfo());
2624 : }
2625 : }
2626 :
2627 0 : for (Articulation* a : articulations()) {
2628 0 : if (!score()->selectionFilter().canSelect(a)) {
2629 0 : continue;
2630 : }
2631 0 : rez = String(u"%1 %2").arg(rez, a->screenReaderInfo());
2632 : }
2633 :
2634 0 : if (arpeggio() && score()->selectionFilter().canSelect(arpeggio())) {
2635 0 : rez = String(u"%1 %2").arg(rez, arpeggio()->screenReaderInfo());
2636 : }
2637 :
2638 0 : if (tremoloTwoChord() && score()->selectionFilter().canSelect(tremoloTwoChord())) {
2639 0 : rez = String(u"%1 %2").arg(rez, tremoloTwoChord()->screenReaderInfo());
2640 : }
2641 :
2642 0 : if (tremoloSingleChord() && score()->selectionFilter().canSelect(tremoloSingleChord())) {
2643 0 : rez = String(u"%1 %2").arg(rez, tremoloSingleChord()->screenReaderInfo());
2644 : }
2645 :
2646 0 : for (EngravingItem* e : el()) {
2647 0 : if (!score()->selectionFilter().canSelect(e)) {
2648 0 : continue;
2649 : }
2650 0 : rez = String(u"%1 %2").arg(rez, e->screenReaderInfo());
2651 : }
2652 :
2653 0 : return String(u"%1 %2").arg(rez, ChordRest::accessibleExtraInfo());
2654 0 : }
2655 :
2656 202 : void Chord::undoChangeProperty(Pid id, const PropertyValue& newValue)
2657 : {
2658 202 : undoChangeProperty(id, newValue, propertyFlags(id));
2659 202 : }
2660 :
2661 : //---------------------------------------------------------
2662 : // undoChangeProperty
2663 : //---------------------------------------------------------
2664 :
2665 316 : void Chord::undoChangeProperty(Pid id, const PropertyValue& newValue, PropertyFlags ps)
2666 : {
2667 316 : if (id == Pid::VISIBLE) {
2668 1 : processSiblings([=](EngravingItem* element) {
2669 2 : element->undoChangeProperty(id, newValue, ps);
2670 2 : }, false);
2671 : }
2672 :
2673 316 : ChordRest::undoChangeProperty(id, newValue, ps);
2674 316 : }
2675 :
2676 24 : std::set<SymId> Chord::articulationSymbolIds() const
2677 : {
2678 24 : std::set<SymId> result;
2679 24 : for (const Articulation* artic: m_articulations) {
2680 0 : result.insert(artic->symId());
2681 : }
2682 :
2683 24 : return result;
2684 0 : }
2685 :
2686 : //---------------------------------------------------------
2687 : // getNoteEventLists
2688 : // Get contents of all NoteEventLists for all notes in
2689 : // the chord.
2690 : //---------------------------------------------------------
2691 :
2692 0 : std::vector<NoteEventList> Chord::getNoteEventLists()
2693 : {
2694 0 : std::vector<NoteEventList> ell;
2695 0 : if (notes().empty()) {
2696 0 : return ell;
2697 : }
2698 0 : ell.reserve(notes().size());
2699 0 : for (size_t i = 0; i < notes().size(); ++i) {
2700 0 : ell.push_back(NoteEventList(notes()[i]->playEvents()));
2701 : }
2702 0 : return ell;
2703 0 : }
2704 :
2705 : //---------------------------------------------------------
2706 : // setNoteEventLists
2707 : // Set contents of all NoteEventLists for all notes in
2708 : // the chord.
2709 : //---------------------------------------------------------
2710 :
2711 341 : void Chord::setNoteEventLists(std::vector<NoteEventList>& ell)
2712 : {
2713 341 : if (notes().empty()) {
2714 0 : return;
2715 : }
2716 341 : IF_ASSERT_FAILED(ell.size() == notes().size()) {
2717 0 : return;
2718 : }
2719 704 : for (size_t i = 0; i < ell.size(); i++) {
2720 363 : notes()[i]->setPlayEvents(ell[i]);
2721 : }
2722 : }
2723 :
2724 : //---------------------------------------------------------
2725 : // styleChanged
2726 : //---------------------------------------------------------
2727 141 : void Chord::styleChanged()
2728 : {
2729 295 : auto updateElementsStyle = [](EngravingItem* e) {
2730 295 : e->styleChanged();
2731 295 : };
2732 141 : scanElements(updateElementsStyle);
2733 141 : }
2734 :
2735 51681 : void Chord::computeKerningExceptions()
2736 : {
2737 51681 : m_allowKerningAbove = true;
2738 51681 : m_allowKerningBelow = true;
2739 53434 : for (Articulation* art : m_articulations) {
2740 1753 : if (art->up()) {
2741 1234 : m_allowKerningAbove = false;
2742 : } else {
2743 519 : m_allowKerningBelow = false;
2744 : }
2745 : }
2746 51681 : if ((m_startEndSlurs.startUp || m_startEndSlurs.endUp) && !ldata()->up) {
2747 565 : m_allowKerningAbove = false;
2748 : }
2749 51681 : if ((m_startEndSlurs.startDown || m_startEndSlurs.endDown) && ldata()->up) {
2750 727 : m_allowKerningBelow = false;
2751 : }
2752 51681 : }
2753 :
2754 251149 : Ornament* Chord::findOrnament(bool forPlayback) const
2755 : {
2756 258216 : for (Articulation* art : m_articulations) {
2757 8617 : if (art->isOrnament()) {
2758 1550 : return toOrnament(art);
2759 : }
2760 : }
2761 259311 : for (Spanner* spanner : m_startingSpanners) {
2762 10123 : if (spanner->isTrill()) {
2763 411 : return toTrill(spanner)->ornament();
2764 : }
2765 : }
2766 249188 : if (forPlayback) {
2767 : // TODO: cleanup.
2768 : // We shouldn't do this kind of special cases, and the DOM shouldn't know anything about playback.
2769 : // This should be in a different function that returns the ornament from the Trill ending on this chord. [MS]
2770 2 : for (Spanner* spanner : m_endingSpanners) {
2771 2 : if (spanner->isTrill()) {
2772 2 : return toTrill(spanner)->ornament();
2773 : }
2774 : }
2775 : }
2776 249186 : return nullptr;
2777 : }
2778 :
2779 : //---------------------------------
2780 : // firstGraceOrNote
2781 : //---------------------------------
2782 213 : Note* Chord::firstGraceOrNote()
2783 : {
2784 213 : GraceNotesGroup& graceNotesBefore = this->graceNotesBefore();
2785 213 : if (!graceNotesBefore.empty()) {
2786 31 : if (Chord* graceNotesBeforeFirstChord = graceNotesBefore.front()) {
2787 31 : return graceNotesBeforeFirstChord->notes().front();
2788 : }
2789 : }
2790 :
2791 182 : return this->notes().back();
2792 : }
2793 :
2794 : //---------------------------------
2795 : // GRACE NOTES
2796 : //---------------------------------
2797 :
2798 67806 : GraceNotesGroup::GraceNotesGroup(DummyParentOr<Chord> c)
2799 67806 : : EngravingItem(ElementType::GRACE_NOTES_GROUP, c), _parent(c.as<Chord>()) {}
2800 :
2801 995 : void GraceNotesGroup::setPos(double x, double y)
2802 : {
2803 995 : EngravingItem::setPos(x, y);
2804 2322 : for (unsigned i = 0; i < this->size(); ++i) {
2805 1327 : Chord* chord = this->at(i);
2806 1327 : chord->mutldata()->move(PointF(x, y));
2807 : }
2808 995 : }
2809 :
2810 2150 : void GraceNotesGroup::addToShape()
2811 : {
2812 5085 : for (Chord* grace : *this) {
2813 2935 : const PointF yOffset = grace->staffOffset();
2814 2935 : staff_idx_t staffIdx = grace->staffIdx();
2815 2935 : staff_idx_t vStaffIdx = grace->vStaffIdx();
2816 2935 : Shape& s = _appendedSegment->staffShape(staffIdx);
2817 2935 : s.add(grace->shape(LD_ACCESS::PASS).translate(grace->pos() + yOffset));
2818 2935 : if (vStaffIdx != staffIdx) {
2819 : // Cross-staff grace notes add their shape to both the origin and the destination staff
2820 0 : Shape& s2 = _appendedSegment->staffShape(vStaffIdx);
2821 0 : s2.add(grace->shape().translate(grace->pos() + yOffset));
2822 : }
2823 : }
2824 2150 : }
2825 : }
|