//============================================================================= // MuseScore // Music Composition & Notation // $Id: accidental.cpp 5242 2012-01-23 17:25:56Z wschweer $ // // Copyright (C) 2002-2011 Werner Schweer // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License version 2 // as published by the Free Software Foundation and appearing in // the file LICENCE.GPL //============================================================================= #include "accidental.h" #include "note.h" #include "symbol.h" #include "sym.h" #include "score.h" #include "staff.h" #include "undo.h" //--------------------------------------------------------- // Acc //--------------------------------------------------------- struct Acc { const char* tag; // for use in xml file const char* name; // translated name AccidentalVal offset; // semitone offset int centOffset; int sym; Acc(const char* t, const char* n, AccidentalVal o, int o2, int s) : tag(t), name(n), offset(o), centOffset(o2), sym(s) {} }; Acc accList[] = { Acc("none", QT_TRANSLATE_NOOP("accidental", "none"), NATURAL, 0, -1), Acc("sharp", QT_TRANSLATE_NOOP("accidental", "sharp"), SHARP, 0, sharpSym), Acc("flat", QT_TRANSLATE_NOOP("accidental", "flat"), FLAT, 0, flatSym), Acc("double sharp", QT_TRANSLATE_NOOP("accidental", "double sharp"), SHARP2, 0, sharpsharpSym), Acc("double flat", QT_TRANSLATE_NOOP("accidental", "double flat"), FLAT2, 0, flatflatSym), Acc("natural", QT_TRANSLATE_NOOP("accidental", "natural"), NATURAL, 0, naturalSym), Acc("flat-slash", QT_TRANSLATE_NOOP("accidental", "flat-slash"), NATURAL, 0, flatslashSym), Acc("flat-slash2", QT_TRANSLATE_NOOP("accidental", "flat-slash2"), NATURAL, 0, flatslash2Sym), Acc("mirrored-flat2", QT_TRANSLATE_NOOP("accidental", "mirrored-flat2"), NATURAL, 0, mirroredflat2Sym), Acc("mirrored-flat", QT_TRANSLATE_NOOP("accidental", "mirrored-flat"), NATURAL, 0, mirroredflatSym), Acc("mirrored-flat-slash", QT_TRANSLATE_NOOP("accidental", "mirrored-flat-slash"), NATURAL, 0, mirroredflatslashSym), Acc("flat-flat-slash", QT_TRANSLATE_NOOP("accidental", "flat-flat-slash"), NATURAL, 0, flatflatslashSym), Acc("sharp-slash", QT_TRANSLATE_NOOP("accidental", "sharp-slash"), NATURAL, 0, sharpslashSym), Acc("sharp-slash2", QT_TRANSLATE_NOOP("accidental", "sharp-slash2"), NATURAL, 0, sharpslash2Sym), Acc("sharp-slash3", QT_TRANSLATE_NOOP("accidental", "sharp-slash3"), NATURAL, 0, sharpslash3Sym), Acc("sharp-slash4", QT_TRANSLATE_NOOP("accidental", "sharp-slash4"), NATURAL, 0, sharpslash4Sym), Acc("sharp arrow up", QT_TRANSLATE_NOOP("accidental", "sharp arrow up"), NATURAL, 0, sharpArrowUpSym), Acc("sharp arrow down", QT_TRANSLATE_NOOP("accidental", "sharp arrow down"), NATURAL, 0, sharpArrowDownSym), Acc("sharp arrow both", QT_TRANSLATE_NOOP("accidental", "sharp arrow both"), NATURAL, 0, sharpArrowBothSym), Acc("flat arrow up", QT_TRANSLATE_NOOP("accidental", "flat arrow up"), NATURAL, 0, flatArrowUpSym), Acc("flat arrow down", QT_TRANSLATE_NOOP("accidental", "flat arrow down"), NATURAL, 0, flatArrowDownSym), Acc("flat arrow both", QT_TRANSLATE_NOOP("accidental", "flat arrow both"), NATURAL, 0, flatArrowBothSym), Acc("natural arrow up", QT_TRANSLATE_NOOP("accidental", "natural arrow up"), NATURAL, 0, naturalArrowUpSym), Acc("natural arrow down", QT_TRANSLATE_NOOP("accidental", "natural arrow down"), NATURAL, 0, naturalArrowDownSym), Acc("natural arrow both", QT_TRANSLATE_NOOP("accidental", "natural arrow both"), NATURAL, 0, naturalArrowBothSym), Acc("sori", QT_TRANSLATE_NOOP("accidental", "sori"), NATURAL, 0, soriSym), Acc("koron", QT_TRANSLATE_NOOP("accidental", "koron"), NATURAL, 0, koronSym) }; //--------------------------------------------------------- // Accidental //--------------------------------------------------------- Accidental::Accidental(Score* s) : Element(s) { setFlags(ELEMENT_MOVABLE | ELEMENT_SELECTABLE); _hasBracket = false; _role = ACC_AUTO; _small = false; _subtype = ACC_NONE; } //--------------------------------------------------------- // read //--------------------------------------------------------- void Accidental::read(const QDomElement& de) { for (QDomElement e = de.firstChildElement(); !e.isNull(); e = e.nextSiblingElement()) { const QString& tag(e.tagName()); bool isInt; int i = e.text().toInt(&isInt); if (tag == "bracket") { if (i == 0 || i == 1) _hasBracket = i; } else if (tag == "subtype") { if (isInt) { _hasBracket = i & 0x8000; i &= ~0x8000; switch(i) { case 0: i = ACC_NONE; break; case 1: case 11: i = ACC_SHARP; break; case 2: case 12: i = ACC_FLAT; break; case 3: case 13: i = ACC_SHARP2; break; case 4: case 14: i = ACC_FLAT2; break; case 5: case 15: i = ACC_NATURAL; break; case 6: i = ACC_SHARP; _hasBracket = true; break; case 7: i = ACC_FLAT; _hasBracket = true; break; case 8: i = ACC_SHARP2; _hasBracket = true; break; case 9: i = ACC_FLAT2; _hasBracket = true; break; case 10: i = ACC_NATURAL; _hasBracket = true; break; case 16: i = ACC_FLAT_SLASH; break; case 17: i = ACC_FLAT_SLASH2; break; case 18: i = ACC_MIRRORED_FLAT2; break; case 19: i = ACC_MIRRORED_FLAT; break; case 20: i = ACC_MIRRIRED_FLAT_SLASH; break; case 21: i = ACC_FLAT_FLAT_SLASH; break; case 22: i = ACC_SHARP_SLASH; break; case 23: i = ACC_SHARP_SLASH2; break; case 24: i = ACC_SHARP_SLASH3; break; case 25: i = ACC_SHARP_SLASH4; break; case 26: i = ACC_SHARP_ARROW_UP; break; case 27: i = ACC_SHARP_ARROW_DOWN; break; case 28: i = ACC_SHARP_ARROW_BOTH; break; case 29: i = ACC_FLAT_ARROW_UP; break; case 30: i = ACC_FLAT_ARROW_DOWN; break; case 31: i = ACC_FLAT_ARROW_BOTH; break; case 32: i = ACC_NATURAL_ARROW_UP; break; case 33: i = ACC_NATURAL_ARROW_DOWN; break; case 34: i = ACC_NATURAL_ARROW_BOTH; break; default: i = 0; break; } setSubtype(AccidentalType(i)); } else setSubtype(e.text()); } else if (tag == "role") { if (i == ACC_AUTO || i == ACC_USER) _role = AccidentalRole(i); } else if (tag == "small") _small = i; else if (Element::readProperties(e)) ; else domError(e); } } //--------------------------------------------------------- // write //--------------------------------------------------------- void Accidental::write(Xml& xml) const { xml.stag(name()); if (_hasBracket) xml.tag("bracket", _hasBracket); if (_role != ACC_AUTO) xml.tag("role", _role); if (_small) xml.tag("small", _small); xml.tag("subtype", accList[_subtype].tag); Element::writeProperties(xml); xml.etag(); } //--------------------------------------------------------- // subTypeUserName //--------------------------------------------------------- const char* Accidental::subtypeUserName() const { return accList[subtype()].name; } //--------------------------------------------------------- // setSubtype //--------------------------------------------------------- void Accidental::setSubtype(const QString& tag) { int n = sizeof(accList)/sizeof(*accList); for (int i = 0; i < n; ++i) { if (accList[i].tag == tag) { setSubtype(AccidentalType(i)); return; } } setSubtype(ACC_NONE); } //--------------------------------------------------------- // symbol //--------------------------------------------------------- int Accidental::symbol() const { return accList[subtype()].sym; } //--------------------------------------------------------- // layout //--------------------------------------------------------- void Accidental::layout() { el.clear(); QRectF r; if (staff() && staff()->isTabStaff()) { //in TAB, accidentals are not shown setbbox(QRectF()); return; } qreal m = magS(); if (_small) m *= score()->styleD(ST_smallNoteMag); QPointF pos; if (_hasBracket) { SymElement e(leftparenSym, 0.0); el.append(e); r |= symbols[score()->symIdx()][leftparenSym].bbox(m); pos = symbols[score()->symIdx()][leftparenSym].attach(m); } int s = symbol(); SymElement e(s, pos.x()); el.append(e); r |= symbols[score()->symIdx()][s].bbox(m); pos += symbols[score()->symIdx()][s].attach(m); if (_hasBracket) { qreal x = pos.x(); // symbols[s].width(m) + symbols[s].bbox(m).x(); SymElement e(rightparenSym, x); el.append(e); r |= symbols[score()->symIdx()][rightparenSym].bbox(m).translated(x, 0.0); } setbbox(r); } //--------------------------------------------------------- // subtype2value // returns the resulting pitch offset //--------------------------------------------------------- AccidentalVal Accidental::subtype2value(AccidentalType st) { return accList[st].offset; } //--------------------------------------------------------- // subtype2name //--------------------------------------------------------- const char* Accidental::subtype2name(AccidentalType st) { return accList[st].tag; } //--------------------------------------------------------- // value2subtype //--------------------------------------------------------- AccidentalType Accidental::value2subtype(AccidentalVal v) { switch(v) { case NATURAL: return ACC_NONE; case SHARP: return ACC_SHARP; case SHARP2: return ACC_SHARP2; case FLAT: return ACC_FLAT; case FLAT2: return ACC_FLAT2; default: qDebug("value2subtype: illegal accidental val %d\n", v); abort(); } return ACC_NONE; } //--------------------------------------------------------- // name2subtype //--------------------------------------------------------- AccidentalType Accidental::name2subtype(const QString& tag) { int n = sizeof(accList)/sizeof(*accList); for (int i = 0; i < n; ++i) { if (accList[i].tag == tag) return AccidentalType(i); } return ACC_NONE; } //--------------------------------------------------------- // draw //--------------------------------------------------------- void Accidental::draw(QPainter* painter) const { if (staff() && staff()->isTabStaff()) //in TAB, accidentals are not shown return; qreal m = magS(); if (_small) m *= score()->styleD(ST_smallNoteMag); painter->setPen(curColor()); foreach(const SymElement& e, el) symbols[score()->symIdx()][e.sym].draw(painter, m, QPointF(e.x, 0.0)); } //--------------------------------------------------------- // acceptDrop //--------------------------------------------------------- bool Accidental::acceptDrop(MuseScoreView*, const QPointF&, Element* e) const { return e->type() == ACCIDENTAL_BRACKET; } //--------------------------------------------------------- // drop //--------------------------------------------------------- Element* Accidental::drop(const DropData& data) { Element* e = data.element; switch(e->type()) { case ACCIDENTAL_BRACKET: _hasBracket = true; // TODO: make undoable // score()->changeAccidental(note(), subtype() | 0x8000); break; default: break; } delete e; return 0; } //--------------------------------------------------------- // undoSetHasBracket //--------------------------------------------------------- void Accidental::undoSetHasBracket(bool val) { score()->undoChangeProperty(this, P_ACCIDENTAL_BRACKET, val); } //--------------------------------------------------------- // undoSetSmall //--------------------------------------------------------- void Accidental::undoSetSmall(bool val) { score()->undoChangeProperty(this, P_SMALL, val); } //--------------------------------------------------------- // getProperty //--------------------------------------------------------- QVariant Accidental::getProperty(P_ID propertyId) const { switch(propertyId) { case P_SMALL: return _small; case P_ACCIDENTAL_BRACKET: return _hasBracket; default: return Element::getProperty(propertyId); } } //--------------------------------------------------------- // setProperty //--------------------------------------------------------- bool Accidental::setProperty(P_ID propertyId, const QVariant& v) { switch(propertyId) { case P_SMALL: _small = v.toBool(); break; case P_ACCIDENTAL_BRACKET: _hasBracket = v.toBool(); break; default: return Element::setProperty(propertyId, v); } return true; } //--------------------------------------------------------- // AccidentalBracket //--------------------------------------------------------- AccidentalBracket::AccidentalBracket(Score* s) : Compound(s) { Symbol* s1 = new Symbol(score()); Symbol* s2 = new Symbol(score()); s1->setSym(leftparenSym); s2->setSym(rightparenSym); addElement(s1, -s1->bbox().x(), 0.0); addElement(s2, s2->bbox().width() - s2->bbox().x(), 0.0); }