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 "elements.h"
24 :
25 : #include "engraving/dom/chord.h"
26 : #include "engraving/dom/clef.h"
27 : #include "engraving/dom/guitarbend.h"
28 : #include "engraving/dom/measure.h"
29 : #include "engraving/dom/measurenumber.h"
30 : #include "engraving/dom/mmrestrange.h"
31 : #include "engraving/dom/property.h"
32 : #include "engraving/dom/score.h"
33 : #include "engraving/dom/slur.h"
34 : #include "engraving/dom/spacer.h"
35 : #include "engraving/dom/system.h"
36 : #include "engraving/dom/tremolotwochord.h"
37 : #include "engraving/dom/trill.h"
38 :
39 : #include "engraving/editing/editnote.h"
40 : #include "engraving/editing/editsystemlocks.h"
41 : #include "engraving/editing/transaction/transaction.h"
42 :
43 : #include "engraving/style/style.h"
44 :
45 : // api
46 : #include "apistructs.h"
47 : #include "part.h"
48 :
49 : #include "log.h"
50 :
51 : using namespace mu::engraving::apiv1;
52 :
53 : //---------------------------------------------------------
54 : // EngravingItem::setOffsetX
55 : //---------------------------------------------------------
56 :
57 0 : void EngravingItem::setOffsetX(qreal offX)
58 : {
59 0 : const qreal offY = element()->offset().y() / element()->spatium();
60 0 : set(mu::engraving::Pid::OFFSET, QPointF(offX, offY));
61 0 : }
62 :
63 : //---------------------------------------------------------
64 : // EngravingItem::setOffsetY
65 : //---------------------------------------------------------
66 :
67 0 : void EngravingItem::setOffsetY(qreal offY)
68 : {
69 0 : const qreal offX = element()->offset().x() / element()->spatium();
70 0 : set(mu::engraving::Pid::OFFSET, QPointF(offX, offY));
71 0 : }
72 :
73 : //---------------------------------------------------------
74 : // Number positions of multimeasure rests
75 : //---------------------------------------------------------
76 :
77 0 : QVariant EngravingItem::mmRestNumberPos() const
78 : {
79 0 : if (!element()->isMMRest()) {
80 0 : return QVariant();
81 : }
82 0 : return element()->style().styleS(Sid::mmRestNumberPos).val() + get(Pid::MMREST_NUMBER_OFFSET).toDouble();
83 : }
84 :
85 0 : void EngravingItem::setMmRestNumberPos(const QVariant& pos)
86 : {
87 0 : if (!element()->isMMRest()) {
88 0 : return;
89 : }
90 0 : set(Pid::MMREST_NUMBER_OFFSET, pos.toDouble() - element()->style().styleS(Sid::mmRestNumberPos).val());
91 : }
92 :
93 0 : void EngravingItem::resetMmRestNumberPos()
94 : {
95 0 : reset(Pid::MMREST_NUMBER_OFFSET);
96 0 : }
97 :
98 : //---------------------------------------------------------
99 : // Number positions of measure repeats
100 : //---------------------------------------------------------
101 :
102 0 : QVariant EngravingItem::measureRepeatNumberPos() const
103 : {
104 0 : if (!element()->isMeasureRepeat()) {
105 0 : return QVariant();
106 : }
107 0 : return element()->style().styleS(Sid::measureRepeatNumberPos).val() + get(Pid::MEASURE_REPEAT_NUMBER_OFFSET).toDouble();
108 : }
109 :
110 0 : void EngravingItem::setMeasureRepeatNumberPos(const QVariant& pos)
111 : {
112 0 : if (!element()->isMeasureRepeat()) {
113 0 : return;
114 : }
115 0 : set(Pid::MEASURE_REPEAT_NUMBER_OFFSET, pos.toDouble() - element()->style().styleS(Sid::measureRepeatNumberPos).val());
116 : }
117 :
118 0 : void EngravingItem::resetMeasureRepeatNumberPos()
119 : {
120 0 : reset(Pid::MEASURE_REPEAT_NUMBER_OFFSET);
121 0 : }
122 :
123 0 : static QRectF scaleRect(const mu::engraving::RectF& rect, double spatium)
124 : {
125 0 : return QRectF(rect.x() / spatium, rect.y() / spatium, rect.width() / spatium, rect.height() / spatium);
126 : }
127 :
128 : //---------------------------------------------------------
129 : // EngravingItem::bbox
130 : // return the element bbox in spatium units, rather than in raster units as stored internally
131 : //---------------------------------------------------------
132 :
133 0 : QRectF EngravingItem::bbox() const
134 : {
135 0 : return scaleRect(element()->ldata()->bbox(), element()->spatium());
136 : }
137 :
138 0 : bool EngravingItem::isHeader() const
139 : {
140 0 : return element()->isClef() && toClef(element())->isHeader();
141 : }
142 :
143 0 : bool EngravingItem::up() const
144 : {
145 0 : if (element()->isChordRest()) {
146 0 : return toChordRest(element())->ldata()->up;
147 0 : } else if (element()->isStem()) {
148 0 : return toStem(element())->up();
149 0 : } else if (element()->isSlur()) {
150 0 : return toSlur(element())->up();
151 0 : } else if (element()->isTie()) {
152 0 : return toTie(element())->up();
153 0 : } else if (element()->isSlurTieSegment()) {
154 0 : return toSlurTieSegment(element())->slurTie()->up();
155 0 : } else if (element()->isArticulation()) {
156 0 : return toArticulation(element())->ldata()->up;
157 0 : } else if (element()->isGuitarBend()) {
158 0 : return toGuitarBend(element())->ldata()->up();
159 0 : } else if (element()->isGuitarBendSegment()) {
160 0 : return toGuitarBendSegment(element())->guitarBend()->ldata()->up();
161 0 : } else if (element()->isBeam()) {
162 0 : return toBeam(element())->up();
163 0 : } else if (element()->isTuplet()) {
164 0 : return toTuplet(element())->isUp();
165 0 : } else if (element()->type() == mu::engraving::ElementType::TREMOLO_TWOCHORD) {
166 0 : return item_cast<const TremoloTwoChord*>(element())->up();
167 : }
168 0 : return false;
169 : }
170 :
171 0 : Fraction* EngravingItem::tick() const
172 : {
173 0 : return wrap(element()->tick());
174 : }
175 :
176 0 : Fraction* EngravingItem::beat() const
177 : {
178 0 : return wrap(element()->beat());
179 : }
180 :
181 : //---------------------------------------------------------
182 : // ChordRest::actualBeamMode
183 : //---------------------------------------------------------
184 :
185 0 : int ChordRest::actualBeamMode(bool beamRests)
186 : {
187 0 : if (chordRest()->isRest() && !beamRests && chordRest()->beamMode() == mu::engraving::BeamMode::AUTO) {
188 0 : return int(mu::engraving::BeamMode::NONE);
189 : }
190 0 : mu::engraving::ChordRest* prev = nullptr;
191 0 : if (!(chordRest()->isChord() && toChord(chordRest())->isGrace())) {
192 0 : mu::engraving::Segment* seg = chordRest()->segment();
193 0 : mu::engraving::Measure* m = seg->measure();
194 0 : while (seg && seg->measure()->system() == m->system()) {
195 0 : seg = seg->prev1(mu::engraving::SegmentType::ChordRest);
196 0 : if (seg && seg->element(chordRest()->track())) {
197 0 : prev = toChordRest(seg->element(chordRest()->track()));
198 0 : break;
199 : }
200 : }
201 : }
202 0 : return int(mu::engraving::Groups::actualBeamMode(chordRest(), prev));
203 : }
204 :
205 : //---------------------------------------------------------
206 : // Segment::elementAt
207 : //---------------------------------------------------------
208 :
209 0 : EngravingItem* Segment::elementAt(int track)
210 : {
211 0 : mu::engraving::EngravingItem* el = segment()->element(track);
212 0 : if (!el) {
213 0 : return nullptr;
214 : }
215 0 : return wrap(el, Ownership::SCORE);
216 : }
217 :
218 0 : Fraction* Segment::fraction() const
219 : {
220 0 : return wrap(segment()->tick());
221 : }
222 :
223 : //---------------------------------------------------------
224 : // Note::setTpc
225 : //---------------------------------------------------------
226 :
227 0 : void Note::setTpc(int val)
228 : {
229 0 : if (!tpcIsValid(val)) {
230 0 : LOGW("PluginAPI::Note::setTpc: invalid tpc: %d", val);
231 0 : return;
232 : }
233 :
234 0 : if (note()->concertPitch()) {
235 0 : set(Pid::TPC1, val);
236 : } else {
237 0 : set(Pid::TPC2, val);
238 : }
239 : }
240 :
241 : //---------------------------------------------------------
242 : // Note::isChildAllowed
243 : /// Check if element type can be a child of note.
244 : /// \since MuseScore 3.3.3
245 : //---------------------------------------------------------
246 :
247 0 : bool Note::isChildAllowed(mu::engraving::ElementType elementType)
248 : {
249 0 : switch (elementType) {
250 0 : case ElementType::NOTEHEAD:
251 : case ElementType::NOTEDOT:
252 : case ElementType::FINGERING:
253 : case ElementType::SYMBOL:
254 : case ElementType::IMAGE:
255 : case ElementType::TEXT:
256 : case ElementType::BEND:
257 : case ElementType::TIE:
258 : case ElementType::PARTIAL_TIE:
259 : case ElementType::LAISSEZ_VIB:
260 : case ElementType::ACCIDENTAL:
261 : case ElementType::TEXTLINE:
262 : case ElementType::NOTELINE:
263 : case ElementType::GLISSANDO:
264 : case ElementType::HAMMER_ON_PULL_OFF:
265 0 : return true;
266 0 : default:
267 0 : return false;
268 : }
269 : }
270 :
271 : //---------------------------------------------------------
272 : // Note::add
273 : /// \since MuseScore 3.3.3
274 : //---------------------------------------------------------
275 :
276 0 : void Note::add(apiv1::EngravingItem* wrapped)
277 : {
278 0 : mu::engraving::EngravingItem* s = wrapped ? wrapped->element() : nullptr;
279 0 : if (s) {
280 : // Ensure that the object has the expected ownership
281 0 : if (wrapped->ownership() == Ownership::SCORE) {
282 0 : LOGW("Note::add: Cannot add this element. The element is already part of the score.");
283 0 : return; // Don't allow operation.
284 : }
285 : // Score now owns the object.
286 0 : wrapped->setOwnership(Ownership::SCORE);
287 :
288 0 : addInternal(note(), s);
289 : }
290 : }
291 :
292 : //---------------------------------------------------------
293 : // Note::addInternal
294 : /// \since MuseScore 3.3.3
295 : //---------------------------------------------------------
296 :
297 0 : void Note::addInternal(mu::engraving::Note* note, mu::engraving::EngravingItem* s)
298 : {
299 : // Provide parentage for element.
300 0 : s->setScore(note->score());
301 0 : s->setOwnershipParent(note);
302 0 : s->setTrack(note->track());
303 :
304 0 : if (s && isChildAllowed(s->type())) {
305 : // Create undo op and add the element.
306 0 : toScore(note->score())->undoAddElement(s);
307 0 : } else if (s) {
308 0 : LOGD("Note::add() not impl. %s", s->typeName());
309 : }
310 0 : }
311 :
312 : //---------------------------------------------------------
313 : // Note::remove
314 : /// \since MuseScore 3.3.3
315 : //---------------------------------------------------------
316 :
317 0 : void Note::remove(apiv1::EngravingItem* wrapped)
318 : {
319 0 : mu::engraving::EngravingItem* s = wrapped->element();
320 0 : if (!s) {
321 0 : LOGW("PluginAPI::Note::remove: Unable to retrieve element. %s", qPrintable(wrapped->name()));
322 0 : } else if (s->ownershipParent() != note()) {
323 0 : LOGW("PluginAPI::Note::remove: The element is not a child of this note. Use removeElement() instead.");
324 0 : } else if (isChildAllowed(s->type())) {
325 0 : note()->score()->deleteItem(s); // Create undo op and remove the element.
326 : } else {
327 0 : LOGD("Note::remove() not impl. %s", s->typeName());
328 : }
329 0 : }
330 :
331 : //---------------------------------------------------------
332 : // DurationElement::ticks
333 : //---------------------------------------------------------
334 :
335 0 : Fraction* DurationElement::ticks() const
336 : {
337 0 : return wrap(durationElement()->ticks());
338 : }
339 :
340 : //---------------------------------------------------------
341 : // DurationElement::changeCRlen
342 : //---------------------------------------------------------
343 :
344 0 : void DurationElement::changeCRlen(Fraction* len)
345 : {
346 0 : if (!durationElement()->isChordRest()) {
347 0 : LOGW("DurationElement::changeCRlen: can only change length for chords or rests");
348 0 : return;
349 : }
350 0 : const mu::engraving::Fraction f = len->fraction();
351 0 : if (!f.isValid() || f.isZero() || f.negative()) {
352 0 : LOGW("DurationElement::changeCRlen: invalid parameter values: %s", qPrintable(f.toString()));
353 0 : return;
354 : }
355 0 : if (durationElement()->isChord() && toChord(durationElement())->isGrace()) {
356 0 : durationElement()->score()->undoChangeChordRestLen(toChord(durationElement()), f);
357 : } else {
358 0 : durationElement()->score()->changeCRlen(toChordRest(durationElement()), f);
359 : }
360 : }
361 :
362 : //---------------------------------------------------------
363 : // DurationElement::globalDuration
364 : //---------------------------------------------------------
365 :
366 0 : Fraction* DurationElement::globalDuration() const
367 : {
368 0 : return wrap(durationElement()->globalTicks());
369 : }
370 :
371 : //---------------------------------------------------------
372 : // DurationElement::actualDuration
373 : //---------------------------------------------------------
374 :
375 0 : Fraction* DurationElement::actualDuration() const
376 : {
377 0 : return wrap(durationElement()->actualTicks());
378 : }
379 :
380 : //---------------------------------------------------------
381 : // DurationElement::parentTuplet
382 : //---------------------------------------------------------
383 :
384 0 : Tuplet* DurationElement::parentTuplet()
385 : {
386 0 : return wrap<Tuplet>(durationElement()->tuplet());
387 : }
388 :
389 : //---------------------------------------------------------
390 : // Chord::setPlayEventType
391 : //---------------------------------------------------------
392 :
393 0 : void Chord::setPlayEventType(mu::engraving::PlayEventType v)
394 : {
395 : // Only create undo operation if the value has changed.
396 0 : if (v != chord()->playEventType()) {
397 0 : chord()->score()->undo(new ChangeChordPlayEventType(chord(), v));
398 : }
399 0 : }
400 :
401 : //---------------------------------------------------------
402 : // Chord::add
403 : //---------------------------------------------------------
404 :
405 0 : void Chord::add(apiv1::EngravingItem* wrapped)
406 : {
407 0 : mu::engraving::EngravingItem* s = wrapped ? wrapped->element() : nullptr;
408 0 : if (s) {
409 : // Ensure that the object has the expected ownership
410 0 : if (wrapped->ownership() == Ownership::SCORE) {
411 0 : LOGW("Chord::add: Cannot add this element. The element is already part of the score.");
412 0 : return; // Don't allow operation.
413 : }
414 : // Score now owns the object.
415 0 : wrapped->setOwnership(Ownership::SCORE);
416 :
417 0 : addInternal(chord(), s);
418 : }
419 : }
420 :
421 : //---------------------------------------------------------
422 : // Chord::addInternal
423 : //---------------------------------------------------------
424 :
425 0 : void Chord::addInternal(mu::engraving::Chord* chord, mu::engraving::EngravingItem* s)
426 : {
427 : // Provide parentage for element.
428 0 : s->setScore(chord->score());
429 0 : s->setOwnershipParent(chord);
430 : // If a note, ensure the element has proper Tpc values. (Will crash otherwise)
431 0 : if (s->isNote()) {
432 0 : s->setTrack(chord->track());
433 0 : toNote(s)->setTpcFromPitch();
434 : }
435 : // Create undo op and add the element.
436 0 : chord->score()->undoAddElement(s);
437 0 : }
438 :
439 : //---------------------------------------------------------
440 : // Chord::remove
441 : //---------------------------------------------------------
442 :
443 0 : void Chord::remove(apiv1::EngravingItem* wrapped)
444 : {
445 0 : mu::engraving::EngravingItem* s = wrapped->element();
446 0 : if (!s) {
447 0 : LOGW("PluginAPI::Chord::remove: Unable to retrieve element. %s", qPrintable(wrapped->name()));
448 0 : } else if (s->ownershipParent() != chord()) {
449 0 : LOGW("PluginAPI::Chord::remove: The element is not a child of this chord. Use removeElement() instead.");
450 0 : } else if (chord()->notes().size() <= 1 && s->isNote()) {
451 0 : LOGW("PluginAPI::Chord::remove: Removal of final note is not allowed.");
452 : } else {
453 0 : chord()->score()->deleteItem(s); // Create undo op and remove the element.
454 : }
455 0 : }
456 :
457 0 : EngravingItem* Measure::vspacerUp(int staffIdx)
458 : {
459 0 : return wrap(measure()->vspacerUp(static_cast<staff_idx_t>(staffIdx)));
460 : }
461 :
462 0 : EngravingItem* Measure::vspacerDown(int staffIdx)
463 : {
464 0 : return wrap(measure()->vspacerDown(static_cast<staff_idx_t>(staffIdx)));
465 : }
466 :
467 0 : EngravingItem* Measure::measureNumber(int staffIdx)
468 : {
469 0 : return wrap(measure()->measureNumber(static_cast<staff_idx_t>(staffIdx)));
470 : }
471 :
472 0 : EngravingItem* Measure::mmRangeText(int staffIdx)
473 : {
474 0 : return wrap(measure()->mmRangeText(static_cast<staff_idx_t>(staffIdx)));
475 : }
476 :
477 0 : bool Measure::corrupted(int staffIdx)
478 : {
479 0 : return measure()->corrupted(static_cast<staff_idx_t>(staffIdx));
480 : }
481 :
482 0 : bool Measure::visible(int staffIdx)
483 : {
484 0 : return measure()->visible(static_cast<staff_idx_t>(staffIdx));
485 : }
486 :
487 0 : bool Measure::stemless(int staffIdx)
488 : {
489 0 : return measure()->stemless(static_cast<staff_idx_t>(staffIdx));
490 : }
491 :
492 0 : Fraction* MeasureBase::tick() const
493 : {
494 0 : return wrap(measureBase()->tick());
495 : }
496 :
497 0 : Fraction* MeasureBase::ticks() const
498 : {
499 0 : return wrap(measureBase()->ticks());
500 : }
501 :
502 0 : void MeasureBase::add(apiv1::EngravingItem* wrapped)
503 : {
504 0 : mu::engraving::EngravingItem* s = wrapped ? wrapped->element() : nullptr;
505 0 : if (s) {
506 : // Ensure that the object has the expected ownership
507 0 : if (wrapped->ownership() == Ownership::SCORE) {
508 0 : LOGW("MeasureBase::add: Cannot add this element. The element is already part of the score.");
509 0 : return; // Don't allow operation.
510 : }
511 : // Score now owns the object.
512 0 : wrapped->setOwnership(Ownership::SCORE);
513 :
514 0 : addInternal(measureBase(), s);
515 : }
516 : }
517 :
518 0 : void MeasureBase::addInternal(mu::engraving::MeasureBase* measureBase, mu::engraving::EngravingItem* s)
519 : {
520 0 : s->setScore(measureBase->score());
521 0 : s->setOwnershipParent(measureBase);
522 0 : measureBase->score()->undoAddElement(s);
523 0 : }
524 :
525 0 : void MeasureBase::remove(apiv1::EngravingItem* wrapped)
526 : {
527 0 : mu::engraving::EngravingItem* s = wrapped->element();
528 0 : if (!s) {
529 0 : LOGW("PluginAPI::MeasureBase::remove: Unable to retrieve element. %s", qPrintable(wrapped->name()));
530 0 : } else if (s->ownershipParent() != measureBase()) {
531 0 : LOGW("PluginAPI::MeasureBase::remove: The element is not a child of this measure base. Use removeElement() instead.");
532 : } else {
533 0 : measureBase()->score()->deleteItem(s); // Create undo op and remove the element.
534 : }
535 0 : }
536 :
537 0 : QRectF System::bbox(int staffIdx)
538 : {
539 0 : mu::engraving::SysStaff* ss = muse::value(system()->staves(), static_cast<staff_idx_t>(staffIdx));
540 0 : return ss ? scaleRect(ss->bbox(), system()->spatium()) : QRectF();
541 : }
542 :
543 0 : qreal System::yOffset(int staffIdx)
544 : {
545 0 : mu::engraving::SysStaff* ss = muse::value(system()->staves(), static_cast<staff_idx_t>(staffIdx));
546 0 : return ss ? ss->yOffset() / system()->spatium() : 0.0;
547 : }
548 :
549 0 : bool System::show(int staffIdx)
550 : {
551 0 : mu::engraving::SysStaff* ss = muse::value(system()->staves(), static_cast<staff_idx_t>(staffIdx));
552 0 : return ss ? ss->show() : false;
553 : }
554 :
555 0 : void System::setHideStaffIfEmpty(int staffIdx, int hide)
556 : {
557 0 : system()->score()->cmdSetHideStaffIfEmptyOverride(static_cast<staff_idx_t>(staffIdx), system(), AutoOnOff(hide));
558 0 : }
559 :
560 0 : void System::setIsLocked(bool locked)
561 : {
562 0 : if (locked == isLocked()) {
563 0 : return;
564 : }
565 0 : Transaction& tx = system()->score()->transactionManager()->currentOrDummyTransaction();
566 0 : const mu::engraving::RangeLock* currentLock = system()->systemLock();
567 0 : if (currentLock && !locked) {
568 0 : EditSystemLocks::undoRemoveSystemLock(tx, currentLock);
569 0 : } else if (!currentLock && locked) {
570 0 : EditSystemLocks::undoAddSystemLock(tx, new mu::engraving::RangeLock(system()->first(), system()->last()));
571 : }
572 : }
573 :
574 : //---------------------------------------------------------
575 : // Page::pageNumber
576 : //---------------------------------------------------------
577 :
578 0 : int Page::pageNumber() const
579 : {
580 0 : return static_cast<int>(page()->pageNumber());
581 : }
582 :
583 : //---------------------------------------------------------
584 : // Staff::part
585 : //---------------------------------------------------------
586 :
587 0 : Part* Staff::part()
588 : {
589 0 : return wrap<Part>(staff()->part());
590 : }
591 :
592 0 : int Staff::clefType(Fraction* tick)
593 : {
594 0 : return int(staff()->clef(tick->fraction()));
595 : }
596 :
597 0 : Fraction* Staff::timeStretch(Fraction* tick)
598 : {
599 0 : return wrap(staff()->timeStretch(tick->fraction()));
600 : }
601 :
602 0 : EngravingItem* Staff::timeSig(Fraction* tick)
603 : {
604 0 : return wrap(staff()->timeSig(tick->fraction()));
605 : }
606 :
607 0 : int Staff::key(Fraction* tick)
608 : {
609 0 : return int(staff()->key(tick->fraction()));
610 : }
611 :
612 0 : IntervalWrapper* Staff::transpose(Fraction* tick)
613 : {
614 0 : return wrap(staff()->transpose(tick->fraction()));
615 : }
616 :
617 0 : QVariantMap Staff::swing(Fraction* f)
618 : {
619 0 : mu::engraving::SwingParameters swingParams = staff()->swing(f->fraction());
620 0 : QVariantMap pluginSwingParams;
621 0 : pluginSwingParams["swingUnit"] = swingParams.swingUnit;
622 0 : pluginSwingParams["swingRatio"] = swingParams.swingRatio;
623 0 : pluginSwingParams["isOn"] = swingParams.isOn();
624 0 : return pluginSwingParams;
625 0 : }
626 :
627 0 : QVariantMap Staff::capo(Fraction* f)
628 : {
629 0 : const mu::engraving::CapoParams& capoParams = staff()->capo(f->fraction());
630 0 : QVariantMap pluginCapoParams;
631 0 : pluginCapoParams["active"] = capoParams.active;
632 0 : pluginCapoParams["fretPosition"] = capoParams.fretPosition;
633 0 : QVariantList ignoredStrings;
634 0 : ignoredStrings.reserve(static_cast<int>(capoParams.ignoredStrings.size()));
635 0 : for (size_t string : capoParams.ignoredStrings) {
636 0 : ignoredStrings.append(static_cast<int>(string));
637 : }
638 0 : pluginCapoParams["ignoredStrings"] = ignoredStrings;
639 0 : return pluginCapoParams;
640 0 : }
641 :
642 0 : bool Staff::stemless(Fraction* tick)
643 : {
644 0 : return staff()->stemless(tick->fraction());
645 : }
646 :
647 0 : qreal Staff::staffHeight(Fraction* tick)
648 : {
649 0 : return staff()->staffHeight(tick->fraction());
650 : }
651 :
652 0 : bool Staff::isPitchedStaff(Fraction* tick)
653 : {
654 0 : return staff()->isPitchedStaff(tick->fraction());
655 : }
656 :
657 0 : bool Staff::isTabStaff(Fraction* tick)
658 : {
659 0 : return staff()->isTabStaff(tick->fraction());
660 : }
661 :
662 0 : bool Staff::isDrumStaff(Fraction* tick)
663 : {
664 0 : return staff()->isDrumStaff(tick->fraction());
665 : }
666 :
667 0 : int Staff::lines(Fraction* tick)
668 : {
669 0 : return staff()->lines(tick->fraction());
670 : }
671 :
672 0 : qreal Staff::lineDistance(Fraction* tick)
673 : {
674 0 : return staff()->lineDistance(tick->fraction());
675 : }
676 :
677 0 : bool Staff::isLinesInvisible(Fraction* tick)
678 : {
679 0 : return staff()->isLinesInvisible(tick->fraction());
680 : }
681 :
682 0 : int Staff::middleLine(Fraction* tick)
683 : {
684 0 : return staff()->middleLine(tick->fraction());
685 : }
686 :
687 0 : int Staff::bottomLine(Fraction* tick)
688 : {
689 0 : return staff()->bottomLine(tick->fraction());
690 : }
691 :
692 0 : qreal Staff::staffMag(Fraction* tick)
693 : {
694 0 : return staff()->staffMag(tick->fraction());
695 : }
696 :
697 0 : qreal Staff::spatium(Fraction* tick)
698 : {
699 0 : return staff()->spatium(tick->fraction());
700 : }
701 :
702 0 : int Staff::pitchOffset(Fraction* tick)
703 : {
704 0 : return staff()->pitchOffset(tick->fraction());
705 : }
706 :
707 0 : bool Staff::isVoiceVisible(int voice)
708 : {
709 0 : return staff()->isVoiceVisible(voice);
710 : }
711 :
712 : //---------------------------------------------------------
713 : // Spanner::ornament
714 : //---------------------------------------------------------
715 :
716 0 : Ornament* Spanner::ornament() const
717 : {
718 0 : if (spanner()->isTrill()) {
719 0 : return wrap<Ornament>(toTrill(spanner())->ornament());
720 : }
721 0 : return nullptr;
722 : }
723 :
724 : //---------------------------------------------------------
725 : // FretDiagram::setDot
726 : // FretDiagram::setMarker
727 : // FretDiagram::setBarre
728 : // FretDiagram::clear
729 : /// When the element is owned by the score, use the undo-aware DOM methods
730 : /// so that modifications are recorded on the undo stack and propagated to
731 : /// all linked clones. When the element is plugin-owned (not yet added to
732 : /// a score), use the direct setters to avoid accessing an invalid undo
733 : /// stack (see ScoreElement::set() in scoreelement.cpp for the same pattern).
734 : //---------------------------------------------------------
735 :
736 4 : void FretDiagram::setDot(int string, int fret, bool add, int dotType)
737 : {
738 4 : if (string < 0 || string >= fretDiagram()->strings()) {
739 1 : LOGW("PluginAPI::FretDiagram::setDot: string %d is out of range (0..%d)", string, fretDiagram()->strings() - 1);
740 1 : return;
741 : }
742 3 : if (fret < 0) {
743 1 : LOGW("PluginAPI::FretDiagram::setDot: fret %d is negative", fret);
744 1 : return;
745 : }
746 2 : if (dotType < int(mu::engraving::FretDotType::NORMAL)
747 2 : || dotType > int(mu::engraving::FretDotType::TRIANGLE)) {
748 1 : LOGW("PluginAPI::FretDiagram::setDot: dotType %d is out of range", dotType);
749 1 : return;
750 : }
751 1 : if (ownership() == Ownership::SCORE) {
752 1 : fretDiagram()->undoSetFretDot(string, fret, add,
753 : static_cast<mu::engraving::FretDotType>(dotType));
754 : } else {
755 0 : fretDiagram()->setDot(string, fret, add,
756 : static_cast<mu::engraving::FretDotType>(dotType));
757 : }
758 : }
759 :
760 3 : void FretDiagram::setMarker(int string, int marker)
761 : {
762 3 : if (string < 0 || string >= fretDiagram()->strings()) {
763 1 : LOGW("PluginAPI::FretDiagram::setMarker: string %d is out of range (0..%d)", string, fretDiagram()->strings() - 1);
764 1 : return;
765 : }
766 2 : if (marker < int(mu::engraving::FretMarkerType::NONE)
767 2 : || marker > int(mu::engraving::FretMarkerType::CROSS)) {
768 1 : LOGW("PluginAPI::FretDiagram::setMarker: marker %d is out of range", marker);
769 1 : return;
770 : }
771 1 : if (ownership() == Ownership::SCORE) {
772 1 : fretDiagram()->undoSetFretMarker(string,
773 : static_cast<mu::engraving::FretMarkerType>(marker));
774 : } else {
775 0 : fretDiagram()->setMarker(string,
776 : static_cast<mu::engraving::FretMarkerType>(marker));
777 : }
778 : }
779 :
780 3 : void FretDiagram::setBarre(int string, int fret, bool add)
781 : {
782 3 : if (string < 0 || string >= fretDiagram()->strings()) {
783 1 : LOGW("PluginAPI::FretDiagram::setBarre: string %d is out of range (0..%d)", string, fretDiagram()->strings() - 1);
784 1 : return;
785 : }
786 2 : if (fret <= 0) {
787 1 : LOGW("PluginAPI::FretDiagram::setBarre: fret %d must be > 0", fret);
788 1 : return;
789 : }
790 1 : if (ownership() == Ownership::SCORE) {
791 1 : fretDiagram()->undoSetFretBarre(string, fret, add);
792 : } else {
793 0 : fretDiagram()->setBarre(string, fret, add);
794 : }
795 : }
796 :
797 1 : void FretDiagram::clear()
798 : {
799 1 : if (ownership() == Ownership::SCORE) {
800 1 : fretDiagram()->undoFretClear();
801 : } else {
802 0 : fretDiagram()->clear();
803 : }
804 1 : }
805 :
806 1 : QVariantList FretDiagram::dots() const
807 : {
808 1 : QVariantList result;
809 2 : for (const auto& [string, dotVec] : fretDiagram()->dots()) {
810 2 : for (const mu::engraving::FretItem::Dot& d : dotVec) {
811 1 : if (!d.exists()) {
812 0 : continue;
813 : }
814 1 : QVariantMap entry;
815 1 : entry["string"] = string;
816 1 : entry["fret"] = d.fret;
817 1 : entry["dotType"] = int(d.dtype);
818 1 : result.append(entry);
819 1 : }
820 : }
821 1 : return result;
822 0 : }
823 :
824 1 : QVariantList FretDiagram::markers() const
825 : {
826 1 : QVariantList result;
827 3 : for (const auto& [string, m] : fretDiagram()->markers()) {
828 2 : if (!m.exists()) {
829 1 : continue;
830 : }
831 1 : QVariantMap entry;
832 1 : entry["string"] = string;
833 1 : entry["markerType"] = int(m.mtype);
834 1 : result.append(entry);
835 1 : }
836 1 : return result;
837 0 : }
838 :
839 1 : QVariantList FretDiagram::barres() const
840 : {
841 1 : QVariantList result;
842 2 : for (const auto& [fret, b] : fretDiagram()->barres()) {
843 1 : if (!b.exists()) {
844 0 : continue;
845 : }
846 1 : QVariantMap entry;
847 1 : entry["fret"] = fret;
848 1 : entry["startString"] = b.startString;
849 1 : entry["endString"] = b.endString;
850 1 : result.append(entry);
851 1 : }
852 1 : return result;
853 0 : }
854 :
855 : //---------------------------------------------------------
856 : // wrap
857 : /// \cond PLUGIN_API \private \endcond
858 : /// Wraps mu::engraving::EngravingItem choosing the correct wrapper type
859 : /// at runtime based on the actual element type.
860 : //---------------------------------------------------------
861 :
862 8 : EngravingItem* mu::engraving::apiv1::wrap(mu::engraving::EngravingItem* e, Ownership own)
863 : {
864 8 : if (!e) {
865 0 : return nullptr;
866 : }
867 :
868 : #define API_WRAP(type) \
869 : if (e->is##type()) { return wrap<type>(to##type(e), own); }
870 :
871 8 : API_WRAP(Tie)
872 8 : API_WRAP(Ornament)
873 8 : API_WRAP(Note)
874 8 : API_WRAP(Chord)
875 8 : API_WRAP(ChordRest)
876 8 : API_WRAP(Tuplet)
877 8 : API_WRAP(DurationElement)
878 8 : API_WRAP(Beam)
879 8 : API_WRAP(Lyrics)
880 8 : API_WRAP(Harmony)
881 7 : API_WRAP(FretDiagram)
882 0 : API_WRAP(Segment)
883 0 : API_WRAP(Measure)
884 0 : API_WRAP(MeasureBase)
885 0 : API_WRAP(System)
886 0 : API_WRAP(Page)
887 0 : API_WRAP(SpannerSegment)
888 0 : API_WRAP(Spanner)
889 0 : return wrap<EngravingItem>(e, own);
890 :
891 : #undef API_WRAP
892 : }
|