//============================================================================= // MuseScore // Music Composition & Notation // // Copyright (C) 2002-2013 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 "marker.h" #include "score.h" #include "sym.h" #include "xml.h" #include "measure.h" namespace Ms { //must be in sync with Marker::Type enum const MarkerTypeItem markerTypeTable[] = { { Marker::Type::SEGNO , QT_TRANSLATE_NOOP("markerType", "Segno") }, { Marker::Type::VARSEGNO, QT_TRANSLATE_NOOP("markerType", "Segno variation")}, { Marker::Type::CODA , QT_TRANSLATE_NOOP("markerType", "Coda") }, { Marker::Type::VARCODA , QT_TRANSLATE_NOOP("markerType", "Varied coda") }, { Marker::Type::CODETTA , QT_TRANSLATE_NOOP("markerType", "Codetta") }, { Marker::Type::FINE , QT_TRANSLATE_NOOP("markerType", "Fine") }, { Marker::Type::TOCODA , QT_TRANSLATE_NOOP("markerType", "To Coda") }, { Marker::Type::USER , QT_TRANSLATE_NOOP("markerType", "Custom") } }; int markerTypeTableSize() { return sizeof(markerTypeTable)/sizeof(MarkerTypeItem) - 1; //-1 for the user defined } //--------------------------------------------------------- // Marker //--------------------------------------------------------- Marker::Marker(Score* s) : TextBase(s) { initSubStyle(SubStyleId::REPEAT_LEFT); _markerType = Type::FINE; setFlags(ElementFlag::MOVABLE | ElementFlag::SELECTABLE | ElementFlag::ON_STAFF); setLayoutToParentWidth(true); } Marker::Marker(SubStyleId ssid, Score* s) : TextBase(s) { initSubStyle(ssid); _markerType = Type::FINE; setFlags(ElementFlag::MOVABLE | ElementFlag::SELECTABLE | ElementFlag::ON_STAFF); setLayoutToParentWidth(true); } //--------------------------------------------------------- // setMarkerType //--------------------------------------------------------- void Marker::setMarkerType(Type t) { _markerType = t; const char* txt = 0; switch (t) { case Type::SEGNO: txt = "segno"; setLabel("segno"); break; case Type::VARSEGNO: txt = "segnoSerpent1"; setLabel("varsegno"); break; case Type::CODA: txt = "coda"; setLabel("codab"); break; case Type::VARCODA: txt = "codaSquare"; setLabel("varcoda"); break; case Type::CODETTA: txt = "codacoda"; setLabel("codetta"); break; case Type::FINE: txt = "Fine"; //TODO-ws initSubStyle(SubStyleId::REPEAT_RIGHT); setLabel("fine"); break; case Type::TOCODA: txt = "To Coda"; //TODO-ws initSubStyle(SubStyle::REPEAT_RIGHT); setLabel("coda"); break; case Type::USER: break; default: qDebug("unknown marker type %d", int(t)); break; } if (empty() && txt) setXmlText(txt); } QString Marker::markerTypeUserName() const { return qApp->translate("markerType", markerTypeTable[static_cast(_markerType)].name.toUtf8().constData()); } //--------------------------------------------------------- // styleChanged //--------------------------------------------------------- void Marker::styleChanged() { setMarkerType(_markerType); } //--------------------------------------------------------- // markerType //--------------------------------------------------------- Marker::Type Marker::markerType(const QString& s) const { if (s == "segno") return Type::SEGNO; else if (s == "varsegno") return Type::VARSEGNO; else if (s == "codab") return Type::CODA; else if (s == "varcoda") return Type::VARCODA; else if (s == "codetta") return Type::CODETTA; else if (s == "fine") return Type::FINE; else if (s == "coda") return Type::TOCODA; else return Type::USER; } //--------------------------------------------------------- // layout //--------------------------------------------------------- void Marker::layout() { setPos(QPointF(0.0, score()->styleP(Sid::markerPosAbove))); TextBase::layout1(); // although normally laid out to parent (measure) width, // force to center over barline if left-aligned if (layoutToParentWidth() && !(align() & (Align::RIGHT | Align::HCENTER))) rxpos() -= width() * 0.5; if (parent() && autoplace()) { setUserOff(QPointF()); int si = staffIdx(); qreal minDistance = 0.5 * spatium(); // score()->styleP(Sid::tempoMinDistance); Shape& s1 = measure()->staffShape(si); Shape s2 = shape().translated(pos()); if (placeAbove()) { qreal d = s2.minVerticalDistance(s1); if (d > -minDistance) { qreal yd = -d - minDistance; rUserYoffset() = yd; s2.translate(QPointF(0.0, yd)); } } else { qreal d = s1.minVerticalDistance(s2); if (d > -minDistance) { qreal yd = d + minDistance; rUserYoffset() = yd; s2.translate(QPointF(0.0, yd)); } } s1.add(s2); } } //--------------------------------------------------------- // read //--------------------------------------------------------- void Marker::read(XmlReader& e) { Type mt = Type::SEGNO; while (e.readNextStartElement()) { const QStringRef& tag(e.name()); if (tag == "label") { QString s(e.readElementText()); setLabel(s); mt = markerType(s); } else if (!TextBase::readProperties(e)) e.unknown(); } setMarkerType(mt); } //--------------------------------------------------------- // write //--------------------------------------------------------- void Marker::write(XmlWriter& xml) const { xml.stag(name()); TextBase::writeProperties(xml); xml.tag("label", _label); xml.etag(); } //--------------------------------------------------------- // undoSetLabel //--------------------------------------------------------- void Marker::undoSetLabel(const QString& s) { undoChangeProperty(Pid::LABEL, s); } //--------------------------------------------------------- // undoSetMarkerType //--------------------------------------------------------- void Marker::undoSetMarkerType(Type t) { undoChangeProperty(Pid::MARKER_TYPE, int(t)); } //--------------------------------------------------------- // getProperty //--------------------------------------------------------- QVariant Marker::getProperty(Pid propertyId) const { switch (propertyId) { case Pid::LABEL: return label(); case Pid::MARKER_TYPE: return int(markerType()); default: break; } return TextBase::getProperty(propertyId); } //--------------------------------------------------------- // setProperty //--------------------------------------------------------- bool Marker::setProperty(Pid propertyId, const QVariant& v) { switch (propertyId) { case Pid::LABEL: setLabel(v.toString()); break; case Pid::MARKER_TYPE: setMarkerType(Type(v.toInt())); break; default: if (!TextBase::setProperty(propertyId, v)) return false; break; } score()->setLayoutAll(); return true; } //--------------------------------------------------------- // propertyDefault //--------------------------------------------------------- QVariant Marker::propertyDefault(Pid propertyId) const { switch (propertyId) { case Pid::LABEL: return QString(); case Pid::MARKER_TYPE: return int(Type::FINE); case Pid::PLACEMENT: return int(Placement::ABOVE); default: break; } return TextBase::propertyDefault(propertyId); } //--------------------------------------------------------- // nextSegmentElement //--------------------------------------------------------- Element* Marker::nextSegmentElement() { Segment* seg; if (markerType() == Marker::Type::FINE) { seg = measure()->last(); return seg->firstElement(staffIdx()); } Measure* prevMeasure = measure()->prevMeasureMM(); if (prevMeasure) { seg = prevMeasure->last(); return seg->firstElement(staffIdx()); } return Element::nextSegmentElement(); } //--------------------------------------------------------- // prevSegmentElement //--------------------------------------------------------- Element* Marker::prevSegmentElement() { //it's the same barline return nextSegmentElement(); } //--------------------------------------------------------- // accessibleInfo //--------------------------------------------------------- QString Marker::accessibleInfo() const { return QString("%1: %2").arg(Element::accessibleInfo()).arg(markerTypeUserName()); } }