//============================================================================= // MuseScore // Music Composition & Notation // // 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 "pedal.h" #include "sym.h" #include "xml.h" #include "system.h" #include "measure.h" #include "chordrest.h" #include "staff.h" #include "score.h" namespace Ms { static const ElementStyle pedalStyle { { Sid::pedalFontFace, Pid::BEGIN_FONT_FACE }, { Sid::pedalFontFace, Pid::CONTINUE_FONT_FACE }, { Sid::pedalFontFace, Pid::END_FONT_FACE }, { Sid::pedalFontSize, Pid::BEGIN_FONT_SIZE }, { Sid::pedalFontSize, Pid::CONTINUE_FONT_SIZE }, { Sid::pedalFontSize, Pid::END_FONT_SIZE }, { Sid::pedalFontStyle, Pid::BEGIN_FONT_STYLE }, { Sid::pedalFontStyle, Pid::CONTINUE_FONT_STYLE }, { Sid::pedalFontStyle, Pid::END_FONT_STYLE }, { Sid::pedalTextAlign, Pid::BEGIN_TEXT_ALIGN }, { Sid::pedalTextAlign, Pid::CONTINUE_TEXT_ALIGN }, { Sid::pedalTextAlign, Pid::END_TEXT_ALIGN }, { Sid::pedalHookHeight, Pid::BEGIN_HOOK_HEIGHT }, { Sid::pedalHookHeight, Pid::END_HOOK_HEIGHT }, { Sid::pedalBeginTextOffset, Pid::BEGIN_TEXT_OFFSET }, { Sid::pedalBeginTextOffset, Pid::CONTINUE_TEXT_OFFSET }, { Sid::pedalBeginTextOffset, Pid::END_TEXT_OFFSET }, { Sid::pedalPlacement, Pid::PLACEMENT }, { Sid::pedalPosBelow, Pid::OFFSET }, }; //--------------------------------------------------------- // layout //--------------------------------------------------------- void PedalSegment::layout() { TextLineBaseSegment::layout(); if (isStyled(Pid::OFFSET)) roffset() = pedal()->propertyDefault(Pid::OFFSET).toPointF(); autoplaceSpannerSegment(); } //--------------------------------------------------------- // getPropertyStyle //--------------------------------------------------------- Sid PedalSegment::getPropertyStyle(Pid pid) const { if (pid == Pid::OFFSET) return spanner()->placeAbove() ? Sid::pedalPosAbove : Sid::pedalPosBelow; return TextLineBaseSegment::getPropertyStyle(pid); } Sid Pedal::getPropertyStyle(Pid pid) const { if (pid == Pid::OFFSET) return placeAbove() ? Sid::pedalPosAbove : Sid::pedalPosBelow; return TextLineBase::getPropertyStyle(pid); } //--------------------------------------------------------- // Pedal //--------------------------------------------------------- Pedal::Pedal(Score* s) : TextLineBase(s) { initElementStyle(&pedalStyle); setLineVisible(true); resetProperty(Pid::BEGIN_TEXT); resetProperty(Pid::CONTINUE_TEXT); resetProperty(Pid::END_TEXT); resetProperty(Pid::LINE_WIDTH); resetProperty(Pid::LINE_STYLE); resetProperty(Pid::BEGIN_HOOK_TYPE); resetProperty(Pid::END_HOOK_TYPE); resetProperty(Pid::BEGIN_TEXT_PLACE); resetProperty(Pid::LINE_VISIBLE); } //--------------------------------------------------------- // read //--------------------------------------------------------- void Pedal::read(XmlReader& e) { if (score()->mscVersion() < 301) e.addSpanner(e.intAttribute("id", -1), this); while (e.readNextStartElement()) { if (!TextLineBase::readProperties(e)) e.unknown(); } } //--------------------------------------------------------- // write //--------------------------------------------------------- void Pedal::write(XmlWriter& xml) const { if (!xml.canWrite(this)) return; xml.stag(this); for (auto i : { Pid::END_HOOK_TYPE, Pid::BEGIN_TEXT, Pid::CONTINUE_TEXT, Pid::END_TEXT, Pid::LINE_VISIBLE, Pid::BEGIN_HOOK_TYPE }) { writeProperty(xml, i); } for (const StyledProperty& spp : *styledProperties()) writeProperty(xml, spp.pid); SLine::writeProperties(xml); xml.etag(); } //--------------------------------------------------------- // createLineSegment //--------------------------------------------------------- static const ElementStyle pedalSegmentStyle { { Sid::pedalPosBelow, Pid::OFFSET }, { Sid::pedalMinDistance, Pid::MIN_DISTANCE }, }; LineSegment* Pedal::createLineSegment() { PedalSegment* p = new PedalSegment(this, score()); p->setTrack(track()); p->initElementStyle(&pedalSegmentStyle); return p; } //--------------------------------------------------------- // propertyDefault //--------------------------------------------------------- QVariant Pedal::propertyDefault(Pid propertyId) const { switch (propertyId) { case Pid::LINE_WIDTH: return score()->styleP(Sid::pedalLineWidth); // return point, not spatium case Pid::LINE_STYLE: return score()->styleV(Sid::pedalLineStyle); case Pid::BEGIN_TEXT: case Pid::CONTINUE_TEXT: case Pid::END_TEXT: return ""; case Pid::BEGIN_TEXT_PLACE: case Pid::CONTINUE_TEXT_PLACE: case Pid::END_TEXT_PLACE: return int(PlaceText::LEFT); case Pid::BEGIN_HOOK_TYPE: case Pid::END_HOOK_TYPE: return int(HookType::NONE); case Pid::LINE_VISIBLE: return true; case Pid::PLACEMENT: return score()->styleV(Sid::pedalPlacement); default: return TextLineBase::propertyDefault(propertyId); } } //--------------------------------------------------------- // linePos // return System() coordinates //--------------------------------------------------------- QPointF Pedal::linePos(Grip grip, System** sys) const { qreal x = 0.0; qreal nhw = score()->noteHeadWidth(); System* s = nullptr; if (grip == Grip::START) { ChordRest* c = toChordRest(startElement()); if (c) { s = c->segment()->system(); x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x(); if (c->type() == ElementType::REST && c->durationType() == TDuration::DurationType::V_MEASURE) x -= c->x(); if (beginHookType() == HookType::HOOK_45) x += nhw * .5; } } else { Element* e = endElement(); ChordRest* c = toChordRest(endElement()); if (!e || e == startElement() || (endHookType() == HookType::HOOK_90)) { // pedal marking on single note or ends with non-angled hook: // extend to next note or end of measure Segment* seg = nullptr; if (!e) seg = startSegment(); else seg = c->segment(); if (seg) { seg = seg->next(); for ( ; seg; seg = seg->next()) { if (seg->segmentType() == SegmentType::ChordRest) { // look for a chord/rest in any voice on this staff bool crFound = false; int track = staffIdx() * VOICES; for (int i = 0; i < VOICES; ++i) { if (seg->element(track + i)) { crFound = true; break; } } if (crFound) break; } else if (seg->segmentType() == SegmentType::EndBarLine) { if (!seg->enabled()) { // disabled barline layout is not reliable // use width of measure instead Measure* m = seg->measure(); s = seg->system(); x = m->width() + m->pos().x() - nhw * 2; seg = nullptr; } break; } } } if (seg) { s = seg->system(); x = seg->pos().x() + seg->measure()->pos().x() - nhw * 2; } } else if (c) { s = c->segment()->system(); x = c->pos().x() + c->segment()->pos().x() + c->segment()->measure()->pos().x(); if (c->type() == ElementType::REST && c->durationType() == TDuration::DurationType::V_MEASURE) x -= c->x(); } if (!s) { Fraction t = tick2(); Measure* m = score()->tick2measure(t); s = m->system(); x = m->tick2pos(t); } if (endHookType() == HookType::HOOK_45) x += nhw * .5; else x += nhw; } *sys = s; return QPointF(x, 0); } }