    //=============================================================================
    //  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
    //=============================================================================

    /**
     \file
     Implementation of classes Clef (partial) and ClefList (complete).
    */

    #include "clef.h"
    #include "measure.h"
    #include "ambitus.h"
    #include "xml.h"
    #include "sym.h"
    #include "symbol.h"
    #include "system.h"
    #include "score.h"
    #include "staff.h"
    #include "segment.h"
    #include "stafftype.h"

    namespace Ms {

    #define TR(a) QT_TRANSLATE_NOOP("clefTable", a)

    // table must be in sync with enum ClefType
    const ClefInfo ClefInfo::clefTable[] = {
    // tag    xmlName    line oCh pOff|-lines for sharps---||---lines for flats--|  symbol                           | name                                   | valid in staff group
    { "G",    "G",         2,  0, 45, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::gClef,                    TR("Treble clef"),                       StaffGroup::STANDARD  },
    { "G15mb","G",         2, -2, 59, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::gClef15mb,                TR("Treble clef 15mb"),                  StaffGroup::STANDARD  },
    { "G8vb", "G",         2, -1, 38, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::gClef8vb,                 TR("Treble clef 8vb"),                   StaffGroup::STANDARD  },
    { "G8va", "G",         2,  1, 52, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::gClef8va,                 TR("Treble clef 8va"),                   StaffGroup::STANDARD  },
    { "G15ma","G",         2,  2, 59, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::gClef15ma,                TR("Treble clef 15ma"),                  StaffGroup::STANDARD  },
    { "G8vbo","G",         2, -1, 38, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::gClef8vbOld,              TR("Double treble clef 8vb on 2nd line"),StaffGroup::STANDARD  },
    { "G8vbp","G",         2,  0, 45, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::gClef8vbParens,           TR("Treble clef optional 8vb"),          StaffGroup::STANDARD  },
    { "G1",   "G",         1,  0, 47, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::gClef,                    TR("French violin clef"),                StaffGroup::STANDARD  },
    { "C1",   "C",         1,  0, 43, { 5, 1, 4, 0, 3,-1, 2, 2, 6, 3, 7, 4, 8, 5 }, SymId::cClef,                    TR("Soprano clef"),                      StaffGroup::STANDARD  },
    { "C2",   "C",         2,  0, 41, { 3, 6, 2, 5, 1, 4, 0, 0, 4, 1, 5, 2, 6, 3 }, SymId::cClef,                    TR("Mezzo-soprano clef"),                StaffGroup::STANDARD  },
    { "C3",   "C",         3,  0, 39, { 1, 4, 0, 3, 6, 2, 5, 5, 2, 6, 3, 7, 4, 8 }, SymId::cClef,                    TR("Alto clef"),                         StaffGroup::STANDARD  },
    { "C4",   "C",         4,  0, 37, { 6, 2, 5, 1, 4, 0, 3, 3, 0, 4, 1, 5, 2, 6 }, SymId::cClef,                    TR("Tenor clef"),                        StaffGroup::STANDARD  },
    { "C5",   "C",         5,  0, 35, { 4, 0, 3,-1, 2, 5, 1, 1, 5, 2, 6, 3, 7, 4 }, SymId::cClef,                    TR("Baritone clef (C clef)"),            StaffGroup::STANDARD  },
    { "C_19C", "G",        2,  0, 45, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::cClefSquare,              TR("C clef, H shape (19th century)"),    StaffGroup::STANDARD  },
    { "C3_F18C", "C",      3,  0, 39, { 1, 4, 0, 3, 6, 2, 5, 5, 2, 6, 3, 7, 4, 8 }, SymId::cClefFrench,              TR("Alto clef (French, 18th century)"),  StaffGroup::STANDARD  },
    { "C4_F18C", "C",      4,  0, 37, { 6, 2, 5, 1, 4, 0, 3, 3, 0, 4, 1, 5, 2, 6 }, SymId::cClefFrench,              TR("Tenor clef (French, 18th century)"), StaffGroup::STANDARD  },
    { "C3_F20C", "C",      3,  0, 39, { 1, 4, 0, 3, 6, 2, 5, 5, 2, 6, 3, 7, 4, 8 }, SymId::cClefFrench20C,           TR("Alto clef (French, 20th century)"),  StaffGroup::STANDARD  },
    { "C4_F20C", "C",      4,  0, 37, { 6, 2, 5, 1, 4, 0, 3, 3, 0, 4, 1, 5, 2, 6 }, SymId::cClefFrench20C,           TR("Tenor clef (French, 20th century)"), StaffGroup::STANDARD  },
    { "F",    "F",         4,  0, 33, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::fClef,                    TR("Bass clef"),                         StaffGroup::STANDARD  },
    { "F15mb","F",         4, -2, 19, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::fClef15mb,                TR("Bass clef 15mb"),                    StaffGroup::STANDARD  },
    { "F8vb", "F",         4, -1, 26, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::fClef8vb,                 TR("Bass clef 8vb"),                     StaffGroup::STANDARD  },
    { "F8va", "F",         4,  1, 40, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::fClef8va,                 TR("Bass clef 8va"),                     StaffGroup::STANDARD  },
    { "F15ma","F",         4,  2, 47, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::fClef15ma,                TR("Bass clef 15ma"),                    StaffGroup::STANDARD  },
    { "F3",   "F",         3,  0, 35, { 4, 0, 3,-1, 2, 5, 1, 1, 5, 2, 6, 3, 7, 4 }, SymId::fClef,                    TR("Baritone clef (F clef)"),            StaffGroup::STANDARD  },
    { "F5",   "F",         5,  0, 31, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::fClef,                    TR("Subbass clef"),                      StaffGroup::STANDARD  },
    { "F_F18C","F",        4,  0, 33, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::fClefFrench,              TR("F clef (French, 18th century)"),     StaffGroup::STANDARD  },
    { "F_19C","F",         4,  0, 33, { 2, 5, 1, 4, 7, 3, 6, 6, 3, 7, 4, 8, 5, 9 }, SymId::fClef19thCentury,         TR("F clef (19th century)"),             StaffGroup::STANDARD  },
    { "PERC", "percussion",2,  0, 45, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::unpitchedPercussionClef1, TR("Percussion"),                        StaffGroup::PERCUSSION},
    { "PERC2","percussion",2,  0, 45, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::unpitchedPercussionClef2, TR("Percussion 2"),                      StaffGroup::PERCUSSION},
    { "TAB",  "TAB",       5,  0,  0, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::sixStringTabClef,         TR("Tablature"),                         StaffGroup::TAB       },
    { "TAB4", "TAB",       5,  0,  0, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::fourStringTabClef,        TR("Tablature 4 lines"),                 StaffGroup::TAB       },
    { "TAB2", "TAB",       5,  0,  0, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::sixStringTabClefSerif,    TR("Tablature Serif"),                   StaffGroup::TAB       },
    { "TAB4_SERIF", "TAB", 5,  0,  0, { 0, 3,-1, 2, 5, 1, 4, 4, 1, 5, 2, 6, 3, 7 }, SymId::fourStringTabClefSerif,   TR("Tablature Serif 4 lines"),           StaffGroup::TAB       },
          };
    #undef TR

    //---------------------------------------------------------
    //   tag2type
    //---------------------------------------------------------

    ClefType ClefInfo::tag2type(const QString& s)
          {
          for (unsigned i = 0; i < sizeof(ClefInfo::clefTable)/sizeof(*ClefInfo::clefTable); ++i) {
                if (clefTable[i]._tag == s)
                      return ClefType(i);
                }
          return ClefType::G;
          }

    //---------------------------------------------------------
    //   Clef
    //---------------------------------------------------------

    Clef::Clef(Score* s)
      : Element(s)
          {
          setFlags(ElementFlag::SELECTABLE | ElementFlag::ON_STAFF);

          _showCourtesy               = true;
          _small                      = false;
          _clefTypes._concertClef     = ClefType::INVALID;
          _clefTypes._transposingClef = ClefType::INVALID;
          }

    Clef::Clef(const Clef& c)
       : Element(c)
          {
          _showCourtesy = c._showCourtesy;
          _small        = c._small;
          _clefTypes    = c._clefTypes;
          }

    //---------------------------------------------------------
    //   mag
    //---------------------------------------------------------

    qreal Clef::mag() const
          {
          qreal mag = staff() ? staff()->mag(tick()) : 1.0;
          if (_small)
                mag *= score()->styleD(StyleIdx::smallClefMag);
          return mag;
          }

    //---------------------------------------------------------
    //   layout
    //---------------------------------------------------------

    void Clef::layout()
          {
          // determine current number of lines and line distance
          int   lines;
          qreal lineDist;
          Segment* clefSeg  = segment();
          int stepOffset;

          // check clef visibility and type compatibility
          if (clefSeg && staff()) {
                int tick             = clefSeg->tick();
                StaffType* staffType = staff()->staffType(tick);
                bool show            = staffType->genClef();        // check staff type allows clef display

                // check clef is compatible with staff type group:
                if (ClefInfo::staffGroup(clefType()) != staffType->group()) {
                      if (tick > 0 && !generated()) // if clef is not generated, hide it
                            show = false;
                      else                          // if generated, replace with initial clef type
                            // TODO : instead of initial staff clef (which is assumed to be compatible)
                            // use the last compatible clef previously found in staff
                            _clefTypes = staff()->clefType(0);
                      }

                // if clef not to show or not compatible with staff group
                if (!show) {
                      setbbox(QRectF());
                      qDebug("Clef::layout(): invisible clef at tick %d(%d) staff %d",
                         segment()->tick(), segment()->tick()/1920, staffIdx());
                      return;
                      }
                lines      = staffType->lines();         // init values from staff type
                lineDist   = staffType->lineDistance().val();
                stepOffset = staffType->stepOffset();
                }
          else {
                lines      = 5;
                lineDist   = 1.0;
                stepOffset = 0;
                }

          qreal _spatium = spatium();
          qreal yoff     = 0.0;
          if (clefType() !=  ClefType::INVALID && clefType() !=  ClefType::MAX) {
                symId = ClefInfo::symId(clefType());
                yoff = lineDist * (lines - ClefInfo::line(clefType()));
                }

          switch (clefType()) {
                case ClefType::C_19C:                            // 19th C clef is like a G clef
                      yoff = lineDist * 1.5;
                      break;
                case ClefType::TAB:                            // TAB clef
                      // on tablature, position clef at half the number of spaces * line distance
                      yoff = lineDist * (lines - 1) * .5;
                      break;
                case ClefType::TAB4:                            // TAB clef 4 strings
                      // on tablature, position clef at half the number of spaces * line distance
                      yoff = lineDist * (lines - 1) * .5;
                      break;
                case ClefType::TAB_SERIF:                           // TAB clef alternate style
                      // on tablature, position clef at half the number of spaces * line distance
                      yoff = lineDist * (lines - 1) * .5;
                      break;
                case ClefType::TAB4_SERIF:                           // TAB clef alternate style
                      // on tablature, position clef at half the number of spaces * line distance
                      yoff = lineDist * (lines - 1) * .5;
                      break;
                case ClefType::PERC:                           // percussion clefs
                      yoff = lineDist * (lines - 1) * 0.5;
                      break;
                case ClefType::PERC2:
                      yoff = lineDist * (lines - 1) * 0.5;
                      break;
                case ClefType::INVALID:
                case ClefType::MAX:
                      qDebug("Clef::layout: invalid type");
                      return;
                default:
                      break;
                }
          // clefs are right aligned to Segment
          QRectF r(symBbox(symId));
          setPos(0.0, yoff * _spatium + (stepOffset * -_spatium));

          setbbox(r);
          }

    //---------------------------------------------------------
    //   draw
    //---------------------------------------------------------

    void Clef::draw(QPainter* painter) const
          {
          if (symId == SymId::noSym || (staff() && !staff()->staffType(tick())->genClef()))
                return;
          painter->setPen(curColor());
          drawSymbol(symId, painter);
          }

    //---------------------------------------------------------
    //   acceptDrop
    //---------------------------------------------------------

    bool Clef::acceptDrop(EditData& data) const
          {
          return (data.element->type() == ElementType::CLEF
             || (/*!generated() &&*/ data.element->type() == ElementType::AMBITUS) );
          }

    //---------------------------------------------------------
    //   drop
    //---------------------------------------------------------

    Element* Clef::drop(EditData& data)
          {
          Element* e = data.element;
          Clef* c = 0;
          if (e->isClef()) {
                Clef* clef = toClef(e);
                ClefType stype  = clef->clefType();
                if (clefType() != stype) {
                      score()->undoChangeClef(staff(), segment(), stype);
                      c = this;
                      }
                }
          else if (e->isAmbitus()) {
                /*if (!generated())*/ {
                      Measure*    meas  = measure();
                      Segment*    segm  = meas->getSegment(SegmentType::Ambitus, meas->tick());
                      if (segm->element(track()))
                            score()->undoRemoveElement(segm->element(track()));
                      Ambitus* r = new Ambitus(score());
                      r->setParent(segm);
                      r->setTrack(track());
                      score()->undoAddElement(r);
                      }
                }
          delete e;
          return c;
          }

    //---------------------------------------------------------
    //   setSmall
    //---------------------------------------------------------

    void Clef::setSmall(bool val)
          {
          if (val != _small) {
                _small = val;
                }
          }

    //---------------------------------------------------------
    //   read
    //---------------------------------------------------------

    void Clef::read(XmlReader& e)
          {
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());
                if (tag == "concertClefType")
                      _clefTypes._concertClef = Clef::clefType(e.readElementText());
                else if (tag == "transposingClefType")
                      _clefTypes._transposingClef = Clef::clefType(e.readElementText());
                else if (tag == "showCourtesyClef")
                      _showCourtesy = e.readInt();
                else if (!Element::readProperties(e))
                      e.unknown();
                }
          if (clefType() == ClefType::INVALID)
                setClefType(ClefType::G);
          }

    //---------------------------------------------------------
    //   write
    //---------------------------------------------------------

    void Clef::write(XmlWriter& xml) const
          {
          xml.stag(name());
          if (_clefTypes._concertClef != ClefType::INVALID)
                xml.tag("concertClefType", ClefInfo::tag(_clefTypes._concertClef));
          if (_clefTypes._transposingClef != ClefType::INVALID)
                xml.tag("transposingClefType", ClefInfo::tag(_clefTypes._transposingClef));
          if (!_showCourtesy)
                xml.tag("showCourtesyClef", _showCourtesy);
          Element::writeProperties(xml);
          xml.etag();
          }

    //---------------------------------------------------------
    //   tick
    //---------------------------------------------------------

    int Clef::tick() const
          {
          return segment() ? segment()->tick() : 0;
          }

    //---------------------------------------------------------
    //   setClefType
    //---------------------------------------------------------

    void Clef::setClefType(const QString& s)
          {
          ClefType ct = clefType(s);
          if (ct == ClefType::INVALID) {
                qDebug("Clef::setSubtype: unknown: <%s>", qPrintable(s));
                ct = ClefType::G;
                }
          setClefType(ct);
          }

    //---------------------------------------------------------
    //   clefTypeName
    //---------------------------------------------------------

    const char* Clef::clefTypeName()
          {
          return ClefInfo::tag(clefType());
          }

    //---------------------------------------------------------
    //   clefType
    //---------------------------------------------------------

    ClefType Clef::clefType(const QString& s)
          {
          return ClefInfo::tag2type(s);
          }

    //---------------------------------------------------------
    //   setClefType
    //---------------------------------------------------------

    void Clef::setClefType(ClefType i)
          {
          if (concertPitch()) {
                _clefTypes._concertClef = i;
                if (_clefTypes._transposingClef == ClefType::INVALID)
                      _clefTypes._transposingClef = i;

                }
          else {
                _clefTypes._transposingClef = i;
                if (_clefTypes._concertClef == ClefType::INVALID)
                      _clefTypes._concertClef = i;
                }
          }

    //---------------------------------------------------------
    //   setConcertClef
    //---------------------------------------------------------

    void Clef::setConcertClef(ClefType val)
          {
          _clefTypes._concertClef = val;
          }

    //---------------------------------------------------------
    //   setTransposingClef
    //---------------------------------------------------------

    void Clef::setTransposingClef(ClefType val)
          {
          _clefTypes._transposingClef = val;
          }

    //---------------------------------------------------------
    //   clefType
    //---------------------------------------------------------

    ClefType Clef::clefType() const
          {
          if (concertPitch())
                return _clefTypes._concertClef;
          else
                return _clefTypes._transposingClef;
          }

    //---------------------------------------------------------
    //   spatiumChanged
    //---------------------------------------------------------

    void Clef::spatiumChanged(qreal oldValue, qreal newValue)
          {
          Element::spatiumChanged(oldValue, newValue);
          layout();
          }

    //---------------------------------------------------------
    //   undoSetShowCourtesy
    //---------------------------------------------------------

    void Clef::undoSetShowCourtesy(bool v)
          {
          undoChangeProperty(P_ID::SHOW_COURTESY, v);
          }

    //---------------------------------------------------------
    //   getProperty
    //---------------------------------------------------------

    QVariant Clef::getProperty(P_ID propertyId) const
          {
          switch(propertyId) {
                case P_ID::SHOW_COURTESY: return showCourtesy();
                case P_ID::SMALL:         return small();
                default:
                      return Element::getProperty(propertyId);
                }
          }

    //---------------------------------------------------------
    //   setProperty
    //---------------------------------------------------------

    bool Clef::setProperty(P_ID propertyId, const QVariant& v)
          {
          switch(propertyId) {
                case P_ID::SHOW_COURTESY: _showCourtesy = v.toBool(); break;
                case P_ID::SMALL:         setSmall(v.toBool()); break;
                default:
                      return Element::setProperty(propertyId, v);
                }
          return true;
          }

    //---------------------------------------------------------
    //   propertyDefault
    //---------------------------------------------------------

    QVariant Clef::propertyDefault(P_ID id) const
          {
          switch(id) {
                case P_ID::SHOW_COURTESY: return true;
                case P_ID::SMALL:         return false;
                default:              return Element::propertyDefault(id);
                }
          }

    //---------------------------------------------------------
    //   nextSegmentElement
    //---------------------------------------------------------

    Element* Clef::nextSegmentElement()
          {
          return segment()->firstInNextSegments(staffIdx());
          }

    //---------------------------------------------------------
    //   prevSegmentElement
    //---------------------------------------------------------

    Element* Clef::prevSegmentElement()
          {
          return segment()->lastInPrevSegments(staffIdx());
          }

    //---------------------------------------------------------
    //   accessibleInfo
    //---------------------------------------------------------

    QString Clef::accessibleInfo() const
          {
          return qApp->translate("clefTable", ClefInfo::name(clefType()));
          }

    //---------------------------------------------------------
    //   clear
    //---------------------------------------------------------

    void Clef::clear()
          {
          setbbox(QRectF());
          symId = SymId::noSym;
          }

    }

↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: symId.

↑ V730 Not all members of a class are initialized inside the constructor. Consider inspecting: symId.