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 : #include "palette.h"
23 :
24 : #include <QMetaEnum>
25 :
26 : #include "io/buffer.h"
27 : #include "io/file.h"
28 : #include "serialization/zipreader.h"
29 : #include "serialization/zipwriter.h"
30 :
31 : #include "translation.h"
32 : #include "mimedatautils.h"
33 :
34 : #include "engraving/dom/actionicon.h"
35 : #include "engraving/dom/articulation.h"
36 : #include "engraving/dom/bracket.h"
37 : #include "engraving/dom/engravingitem.h"
38 : #include "engraving/dom/image.h"
39 : #include "engraving/dom/imageStore.h"
40 : #include "engraving/dom/masterscore.h"
41 :
42 : #include "palettecell.h"
43 : #include "palettecompat.h"
44 :
45 : #include "log.h"
46 :
47 : using namespace mu;
48 : using namespace mu::palette;
49 : using namespace mu::engraving;
50 : using namespace muse;
51 : using namespace muse::io;
52 :
53 0 : Palette::Palette(const muse::modularity::ContextPtr& iocCtx, Type t, QObject* parent)
54 0 : : QObject(parent), muse::Contextable(iocCtx), m_type(t)
55 : {
56 : static int id = 0;
57 0 : m_id = QString::number(++id);
58 0 : }
59 :
60 0 : Palette::~Palette()
61 : {
62 : //! NOTE Prevent double free
63 : //! 1. Deleting by deleting children of QObject
64 : //! 2. Deleting by deleting share pointer
65 0 : for (PaletteCellPtr& c : m_cells) {
66 0 : if (c->parent() == this) {
67 0 : c->setParent(nullptr);
68 : }
69 : }
70 0 : }
71 :
72 0 : QString Palette::id() const
73 : {
74 0 : return m_id;
75 : }
76 :
77 0 : QString Palette::translatedName() const
78 : {
79 0 : return muse::qtrc("palette", m_name.toUtf8());
80 : }
81 :
82 0 : void Palette::retranslate()
83 : {
84 0 : for (const PaletteCellPtr& cell : m_cells) {
85 0 : cell->retranslate();
86 : }
87 0 : }
88 :
89 : /// Returns palette type if it is defined or deduces it from the palette content for
90 : /// custom palettes.
91 0 : Palette::Type Palette::contentType() const
92 : {
93 0 : Type t = type();
94 0 : if (t == Type::Unknown || t == Type::Custom) {
95 0 : t = guessType();
96 : }
97 :
98 0 : if (t == Type::Unknown || t == Type::Custom) {
99 0 : return Type::Clef; // if no type can be deduced, use Clef type by default
100 : }
101 0 : return t;
102 : }
103 :
104 0 : PaletteCellPtr Palette::insertElement(size_t idx, ElementPtr element, const QString& name, qreal mag, const QPointF& offset,
105 : const QString& tag)
106 : {
107 0 : if (element) {
108 : // layout may be important for comparing cells, e.g. filtering "More" popup content
109 0 : engravingRender()->layoutItem(element.get());
110 : }
111 :
112 0 : PaletteCellPtr cell = std::make_shared<PaletteCell>(iocContext(), element, name, mag, offset, tag, this);
113 :
114 0 : auto cellHandler = cellHandlerByPaletteType(m_type);
115 0 : if (cellHandler) {
116 0 : cellHandler(cell);
117 : }
118 :
119 0 : m_cells.emplace(m_cells.begin() + idx, cell);
120 0 : return cell;
121 0 : }
122 :
123 0 : PaletteCellPtr Palette::insertElement(size_t idx, ElementPtr element, const muse::TranslatableString& name, qreal mag,
124 : const QPointF& offset, const QString& tag)
125 : {
126 0 : return insertElement(idx, element, name.str, mag, offset, tag);
127 : }
128 :
129 0 : PaletteCellPtr Palette::insertActionIcon(size_t idx, ActionIconType type, double mag)
130 : {
131 0 : auto icon = std::make_shared<ActionIcon>(paletteScoreProvider()->paletteScore()->dummy());
132 0 : icon->setActionType(type);
133 0 : return insertElement(idx, icon, icon->title().qTranslated(), mag);
134 0 : }
135 :
136 0 : PaletteCellPtr Palette::appendElement(ElementPtr element, const QString& name, qreal mag, const QPointF& offset, const QString& tag)
137 : {
138 0 : if (element) {
139 : // layout may be important for comparing cells, e.g. filtering "More" popup content
140 0 : engravingRender()->layoutItem(element.get());
141 : }
142 :
143 0 : PaletteCellPtr cell = std::make_shared<PaletteCell>(iocContext(), element, name, mag, offset, tag, this);
144 :
145 0 : auto cellHandler = cellHandlerByPaletteType(m_type);
146 0 : if (cellHandler) {
147 0 : cellHandler(cell);
148 : }
149 :
150 0 : m_cells.emplace_back(cell);
151 0 : return cell;
152 0 : }
153 :
154 0 : PaletteCellPtr Palette::appendElement(ElementPtr element, const muse::TranslatableString& name, qreal mag, const QPointF& offset,
155 : const QString& tag)
156 : {
157 0 : return appendElement(element, name.str, mag, offset, tag);
158 : }
159 :
160 0 : PaletteCellPtr Palette::appendActionIcon(ActionIconType type, double mag)
161 : {
162 0 : auto icon = std::make_shared<ActionIcon>(paletteScoreProvider()->paletteScore()->dummy());
163 0 : icon->setActionType(type);
164 0 : return appendElement(icon, icon->title().qTranslated(), mag);
165 0 : }
166 :
167 0 : bool Palette::insertCell(size_t idx, PaletteCellPtr cell)
168 : {
169 0 : return insertCells(idx, { cell });
170 0 : }
171 :
172 0 : bool Palette::insertCells(size_t idx, std::vector<PaletteCellPtr> cells)
173 : {
174 0 : if (idx > m_cells.size()) {
175 0 : return false;
176 : }
177 :
178 0 : for (PaletteCellPtr& c : cells) {
179 0 : c->setParent(this);
180 : }
181 :
182 0 : m_cells.insert(m_cells.begin() + idx, std::make_move_iterator(cells.begin()),
183 : std::make_move_iterator(cells.end()));
184 :
185 0 : return true;
186 : }
187 :
188 0 : bool Palette::removeCell(PaletteCellPtr cell)
189 : {
190 0 : return removeCells({ cell });
191 0 : }
192 :
193 0 : bool Palette::removeCells(std::vector<PaletteCellPtr> cells)
194 : {
195 0 : for (PaletteCellPtr& c : cells) {
196 0 : c->setParent(nullptr);
197 0 : m_cells.erase(std::remove(m_cells.begin(), m_cells.end(), c), m_cells.end());
198 : }
199 :
200 0 : return true;
201 : }
202 :
203 0 : PaletteCellPtr Palette::takeCell(size_t idx)
204 : {
205 0 : std::vector<PaletteCellPtr> cells = takeCells(idx, 1);
206 0 : return !cells.empty() ? cells.front() : nullptr;
207 0 : }
208 :
209 0 : std::vector<PaletteCellPtr> Palette::takeCells(size_t idx, size_t count)
210 : {
211 0 : std::vector<PaletteCellPtr> removedCells;
212 0 : removedCells.reserve(count);
213 :
214 0 : if (idx + count > m_cells.size()) {
215 0 : return removedCells;
216 : }
217 :
218 0 : auto removeBegin = m_cells.begin() + idx;
219 0 : auto removeEnd = removeBegin + count;
220 :
221 0 : removedCells.insert(removedCells.end(), std::make_move_iterator(removeBegin), std::make_move_iterator(removeEnd));
222 0 : m_cells.erase(removeBegin, removeEnd);
223 :
224 0 : for (PaletteCellPtr& c : removedCells) {
225 0 : c->setParent(nullptr);
226 : }
227 :
228 0 : return removedCells;
229 0 : }
230 :
231 : // Helper function to compare two Elements
232 0 : static bool isEquivalent(const EngravingItem& e1, const EngravingItem& e2)
233 : {
234 0 : return e1.type() == e2.type()
235 0 : && e1.subtype() == e2.subtype()
236 0 : && e1.mimeData() == e2.mimeData();
237 : }
238 :
239 0 : int Palette::indexOfCell(const PaletteCell& cell, bool matchName) const
240 : {
241 0 : const EngravingItem* el = cell.element.get();
242 0 : if (!el) {
243 0 : return -1;
244 : }
245 :
246 0 : for (size_t i = 0; i < m_cells.size(); ++i) {
247 0 : const PaletteCell& localCell = *m_cells[i];
248 0 : if (matchName && localCell.name != cell.name) {
249 0 : continue;
250 : }
251 :
252 0 : const EngravingItem* exElement = localCell.element.get();
253 0 : if (exElement && !isEquivalent(*exElement, *el)) {
254 0 : continue;
255 : }
256 :
257 0 : if (localCell.drawStaff != cell.drawStaff
258 0 : || localCell.xoffset != cell.xoffset
259 0 : || localCell.yoffset != cell.yoffset
260 0 : || localCell.mag != cell.mag
261 0 : || localCell.readOnly != cell.readOnly
262 0 : || localCell.visible != cell.visible
263 0 : || localCell.custom != cell.custom
264 : ) {
265 0 : continue;
266 : }
267 :
268 0 : return int(i);
269 : }
270 :
271 0 : return -1;
272 : }
273 :
274 0 : QSize Palette::scaledGridSize() const
275 : {
276 0 : return gridSize() * configuration()->paletteScaling();
277 : }
278 :
279 0 : bool Palette::read(XmlReader& e, bool pasteMode)
280 : {
281 0 : m_name = e.attribute("name");
282 0 : m_type = Type::Unknown;
283 0 : while (e.readNextStartElement()) {
284 0 : const AsciiStringView tag(e.name());
285 0 : if (tag == "gridWidth") {
286 0 : m_gridSize.setWidth(e.readDouble());
287 0 : } else if (tag == "gridHeight") {
288 0 : m_gridSize.setHeight(e.readDouble());
289 0 : } else if (tag == "mag") {
290 0 : m_mag = e.readDouble();
291 0 : } else if (tag == "grid") {
292 0 : m_drawGrid = e.readInt();
293 0 : } else if (tag == "yoffset") {
294 0 : m_yOffset = e.readDouble();
295 0 : } else if (tag == "drumPalette") { // obsolete
296 0 : e.skipCurrentElement();
297 0 : } else if (tag == "type") {
298 0 : ByteArray ba = e.readText().toAscii();
299 0 : bool ok = true;
300 0 : const int t = QMetaEnum::fromType<Type>().keyToValue(ba.constChar(), &ok);
301 0 : if (ok) {
302 0 : m_type = Type(t);
303 : }
304 0 : } else if (tag == "visible") {
305 0 : m_isVisible = e.readBool();
306 0 : } else if (pasteMode && tag == "expanded") {
307 0 : m_isExpanded = e.readBool();
308 0 : } else if (tag == "editable") {
309 0 : m_isEditable = e.readBool();
310 0 : } else if (tag == "Cell") {
311 0 : PaletteCellPtr cell = std::make_shared<PaletteCell>(iocContext(), this);
312 0 : if (!cell->read(e, pasteMode)) {
313 0 : continue;
314 : }
315 :
316 0 : auto cellHandler = cellHandlerByPaletteType(m_type);
317 0 : if (cellHandler) {
318 0 : cellHandler(cell);
319 : }
320 :
321 0 : m_cells.push_back(cell);
322 0 : } else {
323 0 : e.unknown();
324 : }
325 : }
326 : // (from old palette): make sure hgrid and vgrid are not 0, we divide by them later
327 0 : if (m_gridSize.width() <= 0) {
328 0 : m_gridSize.setWidth(28);
329 : }
330 0 : if (m_gridSize.height() <= 0) {
331 0 : m_gridSize.setHeight(28);
332 : }
333 :
334 0 : if (m_type == Type::Unknown) {
335 0 : m_type = guessType();
336 : }
337 :
338 0 : PaletteCompat::removeOldItemsIfNeeded(*this);
339 0 : PaletteCompat::addNewItemsIfNeeded(*this, paletteScoreProvider()->paletteScore());
340 :
341 0 : return true;
342 : }
343 :
344 0 : QByteArray Palette::toMimeData() const
345 : {
346 0 : return ::toMimeData(this);
347 : }
348 :
349 0 : void Palette::write(XmlWriter& xml, bool pasteMode) const
350 : {
351 0 : xml.startElement("Palette", { { "name", m_name } });
352 0 : xml.tag("type", QMetaEnum::fromType<Type>().valueToKey(int(m_type)));
353 0 : xml.tag("gridWidth", m_gridSize.width());
354 0 : xml.tag("gridHeight", m_gridSize.height());
355 0 : xml.tag("mag", m_mag);
356 0 : if (m_drawGrid) {
357 0 : xml.tag("grid", m_drawGrid);
358 : }
359 :
360 0 : if (!RealIsNull(m_yOffset)) {
361 0 : xml.tag("yoffset", m_yOffset);
362 : }
363 :
364 0 : xml.tag("visible", m_isVisible, true);
365 0 : xml.tag("editable", m_isEditable, true);
366 :
367 0 : if (pasteMode) {
368 0 : xml.tag("expanded", m_isExpanded, false);
369 : }
370 :
371 0 : for (const PaletteCellPtr& cell : m_cells) {
372 0 : if (!cell) { // from old palette, not sure if it is still needed
373 0 : xml.tag("Cell");
374 0 : continue;
375 : }
376 0 : cell->write(xml, pasteMode);
377 : }
378 0 : xml.endElement();
379 0 : }
380 :
381 0 : PalettePtr Palette::fromMimeData(const QByteArray& data, const muse::modularity::ContextPtr& iocCtx)
382 : {
383 0 : return ::fromMimeData<Palette>(data, "Palette", iocCtx);
384 : }
385 :
386 0 : bool Palette::readFromFile(const QString& p)
387 : {
388 0 : QString path(p);
389 0 : if (!path.endsWith(".mpal", Qt::CaseInsensitive)) {
390 0 : path += ".mpal";
391 : }
392 :
393 0 : ZipReader f(path);
394 0 : if (!f.exists()) {
395 0 : LOGD("palette <%s> not found", qPrintable(path));
396 0 : return false;
397 : }
398 0 : m_cells.clear();
399 :
400 0 : ByteArray ba = f.fileData("META-INF/container.xml");
401 :
402 0 : XmlReader e(ba);
403 : // extract first rootfile
404 0 : QString rootfile;
405 0 : std::vector<std::string> images;
406 0 : while (e.readNextStartElement()) {
407 0 : if (e.name() != "container") {
408 0 : e.unknown();
409 0 : break;
410 : }
411 0 : while (e.readNextStartElement()) {
412 0 : if (e.name() != "rootfiles") {
413 0 : e.unknown();
414 0 : break;
415 : }
416 0 : while (e.readNextStartElement()) {
417 0 : const AsciiStringView tag(e.name());
418 :
419 0 : if (tag == "rootfile") {
420 0 : if (rootfile.isEmpty()) {
421 0 : rootfile = e.attribute("full-path");
422 : }
423 0 : e.readNext();
424 0 : } else if (tag == "file") {
425 0 : images.push_back(e.readAsciiText().ascii());
426 : } else {
427 0 : e.unknown();
428 : }
429 : }
430 : }
431 : }
432 : //
433 : // load images
434 : //
435 0 : for (const std::string& s : images) {
436 0 : imageStore.add(s, f.fileData(s));
437 : }
438 :
439 0 : if (rootfile.isEmpty()) {
440 0 : LOGD("can't find rootfile in: %s", qPrintable(path));
441 0 : return false;
442 : }
443 :
444 0 : ba = f.fileData(rootfile.toStdString());
445 0 : e.setData(ba);
446 0 : while (e.readNextStartElement()) {
447 0 : if (e.name() == "museScore") {
448 0 : QString version = e.attribute("version");
449 0 : QStringList sl = version.split('.');
450 0 : int mscVersion = sl[0].toInt() * 100 + sl[1].toInt();
451 0 : paletteScoreProvider()->paletteScore()->setMscVersion(mscVersion);
452 :
453 0 : while (e.readNextStartElement()) {
454 0 : if (e.name() == "Palette") {
455 0 : read(e, false);
456 : } else {
457 0 : e.unknown();
458 : }
459 : }
460 0 : } else {
461 0 : e.unknown();
462 : }
463 : }
464 0 : return true;
465 0 : }
466 :
467 0 : bool Palette::writeToFile(const QString& p) const
468 : {
469 0 : std::set<ImageStoreItem*> images;
470 0 : for (const PaletteCellPtr& cell : m_cells) {
471 0 : if (!cell || !cell->element || !cell->element->isImage()) {
472 0 : continue;
473 : }
474 0 : images.insert(toImage(cell->element.get())->storeItem());
475 : }
476 :
477 0 : QString path(p);
478 0 : if (!path.endsWith(".mpal", Qt::CaseInsensitive)) {
479 0 : path += ".mpal";
480 : }
481 :
482 0 : auto zipBuf = Buffer::opened(IODevice::WriteOnly);
483 0 : ZipWriter f(&zipBuf);
484 0 : if (f.hasError()) {
485 0 : showWritingPaletteError(path);
486 0 : return false;
487 : }
488 :
489 0 : auto cbuf = Buffer::opened(IODevice::ReadWrite);
490 0 : XmlWriter xml(&cbuf);
491 0 : xml.startDocument();
492 0 : xml.startElement("container");
493 0 : xml.startElement("rootfiles");
494 0 : xml.startElement("rootfile", { { "full-path", "palette.xml" } });
495 0 : xml.endElement();
496 0 : for (const ImageStoreItem* ip : images) {
497 0 : std::string ipath = "Pictures/" + ip->hashName();
498 0 : xml.tag("file", ipath);
499 0 : }
500 0 : xml.endElement();
501 0 : xml.endElement();
502 0 : xml.flush();
503 0 : cbuf.seek(0);
504 : //f.addDirectory("META-INF");
505 : //f.addDirectory("Pictures");
506 0 : f.addFile("META-INF/container.xml", cbuf.data());
507 :
508 : // save images
509 0 : for (const ImageStoreItem* ip : images) {
510 0 : std::string ipath = "Pictures/" + ip->hashName();
511 0 : f.addFile(ipath, ip->buffer());
512 0 : }
513 : {
514 0 : Buffer cbuf1 = Buffer::opened(IODevice::ReadWrite);
515 0 : XmlWriter xml1(&cbuf1);
516 0 : xml1.startDocument();
517 0 : xml1.startElement("museScore", { { "version", Constants::MSC_VERSION_STR } });
518 0 : write(xml1, false);
519 0 : xml1.endElement();
520 0 : xml1.flush();
521 0 : cbuf1.close();
522 0 : f.addFile("palette.xml", cbuf1.data());
523 0 : }
524 0 : f.close();
525 0 : if (f.hasError()) {
526 0 : showWritingPaletteError(path);
527 0 : return false;
528 : }
529 :
530 0 : if (!File::writeFile(path, zipBuf.data())) {
531 0 : showWritingPaletteError(path);
532 0 : return false;
533 : }
534 :
535 0 : File::setPermissionsAllowedForAll(path);
536 0 : return true;
537 0 : }
538 :
539 0 : void Palette::showWritingPaletteError(const QString& path) const
540 : {
541 0 : std::string title = muse::trc("palette", "Writing palette file");
542 0 : std::string message = muse::qtrc("palette", "Writing palette file\n%1\nfailed.").arg(path).toStdString();
543 0 : interactive()->error(title, message);
544 0 : }
545 :
546 0 : Palette::Type Palette::guessType() const
547 : {
548 0 : if (m_cells.empty()) {
549 0 : return Type::Custom;
550 : }
551 :
552 0 : const EngravingItem* e = nullptr;
553 0 : for (const PaletteCellPtr& cell : m_cells) {
554 0 : if (cell->element) {
555 0 : e = cell->element.get();
556 0 : break;
557 : }
558 : }
559 :
560 0 : if (!e) {
561 0 : return Type::Custom;
562 : }
563 :
564 0 : switch (e->type()) {
565 0 : case ElementType::CLEF:
566 0 : return Type::Clef;
567 0 : case ElementType::KEYSIG:
568 0 : return Type::KeySig;
569 0 : case ElementType::TIMESIG:
570 0 : return Type::TimeSig;
571 0 : case ElementType::BRACKET:
572 : case ElementType::BRACKET_ITEM:
573 0 : return Type::Bracket;
574 0 : case ElementType::ACCIDENTAL:
575 0 : return Type::Accidental;
576 0 : case ElementType::ARTICULATION:
577 : case ElementType::BEND:
578 0 : return toArticulation(e)->isOrnament() ? Type::Ornament : Type::Articulation;
579 0 : case ElementType::FERMATA:
580 0 : return Type::Articulation;
581 0 : case ElementType::BREATH:
582 0 : return Type::Breath;
583 0 : case ElementType::NOTEHEAD:
584 0 : return Type::NoteHead;
585 0 : case ElementType::BAR_LINE:
586 0 : return Type::BarLine;
587 0 : case ElementType::ARPEGGIO:
588 : case ElementType::CHORD_BRACKET:
589 : case ElementType::GLISSANDO:
590 0 : return Type::Arpeggio;
591 0 : case ElementType::TREMOLO_SINGLECHORD:
592 : case ElementType::TREMOLO_TWOCHORD:
593 0 : return Type::Tremolo;
594 0 : case ElementType::TEMPO_TEXT:
595 0 : return Type::Tempo;
596 0 : case ElementType::DYNAMIC:
597 0 : return Type::Dynamic;
598 0 : case ElementType::FINGERING:
599 0 : return Type::Fingering;
600 0 : case ElementType::MARKER:
601 : case ElementType::JUMP:
602 : case ElementType::MEASURE_REPEAT:
603 0 : return Type::Repeat;
604 0 : case ElementType::FRET_DIAGRAM:
605 0 : return Type::FretboardDiagram;
606 0 : case ElementType::BAGPIPE_EMBELLISHMENT:
607 0 : return Type::BagpipeEmbellishment;
608 0 : case ElementType::LAYOUT_BREAK:
609 : case ElementType::SPACER:
610 0 : return Type::Layout;
611 0 : case ElementType::SYMBOL:
612 0 : return Type::Accordion;
613 0 : case ElementType::HARP_DIAGRAM:
614 0 : return Type::Harp;
615 0 : case ElementType::STRING_TUNINGS:
616 0 : return Type::StringTunings;
617 0 : case ElementType::ACTION_ICON: {
618 0 : const ActionIcon* action = toActionIcon(e);
619 0 : ActionIconType actionType = action->actionType();
620 :
621 : static const std::set<ActionIconType> beamTypes = {
622 : ActionIconType::BEAM_AUTO,
623 : ActionIconType::BEAM_NONE,
624 : ActionIconType::BEAM_BREAK_LEFT,
625 : ActionIconType::BEAM_BREAK_INNER_8TH,
626 : ActionIconType::BEAM_BREAK_INNER_16TH,
627 : ActionIconType::BEAM_JOIN,
628 : ActionIconType::BEAM_FEATHERED_DECELERATE,
629 : ActionIconType::BEAM_FEATHERED_ACCELERATE
630 0 : };
631 :
632 : static const std::set<ActionIconType> graceTypes = {
633 : ActionIconType::ACCIACCATURA,
634 : ActionIconType::APPOGGIATURA,
635 : ActionIconType::GRACE4,
636 : ActionIconType::GRACE16,
637 : ActionIconType::GRACE32,
638 : ActionIconType::GRACE8_AFTER,
639 : ActionIconType::GRACE16_AFTER,
640 : ActionIconType::GRACE32_AFTER
641 0 : };
642 :
643 : static const std::set<ActionIconType> layoutTypes = {
644 : ActionIconType::VFRAME,
645 : ActionIconType::HFRAME,
646 : ActionIconType::TFRAME,
647 : ActionIconType::FFRAME,
648 : ActionIconType::STAFF_TYPE_CHANGE,
649 : ActionIconType::MEASURE
650 0 : };
651 :
652 0 : if (beamTypes.contains(actionType)) {
653 0 : return Type::Beam;
654 : }
655 0 : if (graceTypes.contains(actionType)) {
656 0 : return Type::GraceNote;
657 : }
658 0 : if (layoutTypes.contains(actionType)) {
659 0 : return Type::Layout;
660 : }
661 0 : return Type::Custom;
662 : }
663 0 : default: {
664 0 : if (e->isSpanner()) {
665 0 : return Type::Line;
666 : }
667 0 : if (e->isTextBase()) {
668 0 : return Type::Text;
669 : }
670 : }
671 : }
672 :
673 0 : return Type::Custom;
674 : }
675 :
676 0 : std::function<void(PaletteCellPtr)> Palette::cellHandlerByPaletteType(const Palette::Type& type) const
677 : {
678 0 : switch (type) {
679 0 : case Type::Bracket:
680 0 : return [](PaletteCellPtr cellPtr) {
681 0 : if (!cellPtr || !cellPtr->element || !cellPtr->element.get()->isBracket()) {
682 0 : return;
683 : }
684 :
685 0 : Bracket* bracket = toBracket(cellPtr->element.get());
686 :
687 0 : if (bracket->bracketType() == BracketType::BRACE) {
688 0 : bracket->setStaffSpan(0, 1);
689 0 : cellPtr->mag = 1.2;
690 : }
691 0 : };
692 0 : default:
693 0 : return nullptr;
694 : }
695 : }
|