    //=============================================================================
    //  MuseScore
    //  Music Composition & Notation
    //
    //  Copyright (C) 2010-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 "bend.h"
    #include "score.h"
    #include "undo.h"
    #include "staff.h"
    #include "chord.h"
    #include "note.h"
    #include "xml.h"

    namespace Ms {

    //---------------------------------------------------------
    //   styledProperties
    //---------------------------------------------------------

    static constexpr std::array<StyledProperty,5> styledProperties {{
          { StyleIdx::bendFontFace,      P_ID::FONT_FACE },
          { StyleIdx::bendFontSize,      P_ID::FONT_SIZE },
          { StyleIdx::bendFontBold,      P_ID::FONT_BOLD },
          { StyleIdx::bendFontItalic,    P_ID::FONT_ITALIC },
          { StyleIdx::bendFontUnderline, P_ID::FONT_UNDERLINE }
          }};

    //---------------------------------------------------------
    //   label
    //---------------------------------------------------------

    static const char* label[] = {
          "", "1/4", "1/2", "3/4", "full",
          "1 1/4", "1 1/2", "1 3/4", "2",
          "2 1/4", "2 1/2", "2 3/4", "3"
          };

    //---------------------------------------------------------
    //   Bend
    //---------------------------------------------------------

    Bend::Bend(Score* s)
       : Element(s)
          {
          setFlags(ElementFlag::MOVABLE | ElementFlag::SELECTABLE);
          }

    //---------------------------------------------------------
    //   font
    //---------------------------------------------------------

    QFont Bend::font(qreal sp) const
          {
          QFont f(fontFace);
          f.setBold(fontBold);
          f.setItalic(fontItalic);
          f.setUnderline(fontUnderline);
          qreal m = fontSize;
          m *= sp / SPATIUM20;

          f.setPointSizeF(m);
          return f;
          }

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

    void Bend::layout()
          {
          // during mtest, there may be no score. If so, exit.
          if (!score())
                return;

          qreal _spatium = spatium();

          if (staff() && !staff()->isTabStaff(tick())) {
                setbbox(QRectF());
                if (!parent()) {
                      noteWidth = -_spatium*2;
                      notePos   = QPointF(0.0, _spatium*3);
                      }
                }

          _lw        = _spatium * 0.15;
          Note* note = toNote(parent());
          if (note == 0) {
                noteWidth = 0.0;
                notePos = QPointF();
                }
          else {
                notePos   = note->pos();
                noteWidth = note->width();
                }
          QRectF bb;

          QFontMetricsF fm(font(_spatium));

          int n   = _points.size();
          qreal x = noteWidth;
          qreal y = -_spatium * .8;
          qreal x2, y2;

          qreal aw = _spatium * .5;
          QPolygonF arrowUp;
          arrowUp << QPointF(0, 0) << QPointF(aw*.5, aw) << QPointF(-aw*.5, aw);
          QPolygonF arrowDown;
          arrowDown << QPointF(0, 0) << QPointF(aw*.5, -aw) << QPointF(-aw*.5, -aw);

          for (int pt = 0; pt < n; ++pt) {
                if (pt == (n-1))
                      break;
                int pitch = _points[pt].pitch;
                if (pt == 0 && pitch) {
                      y2 = -notePos.y() -_spatium * 2;
                      x2 = x;
                      bb |= QRectF(x, y, x2-x, y2-y);

                      bb |= arrowUp.translated(x2, y2 + _spatium * .2).boundingRect();

                      int idx = (pitch + 12)/25;
                      const char* l = label[idx];
                      bb |= fm.boundingRect(QRectF(x2, y2, 0, 0),
                         Qt::AlignHCenter | Qt::AlignBottom | Qt::TextDontClip, QString(l));
                      y = y2;
                      }
                if (pitch == _points[pt+1].pitch) {
                      if (pt == (n-2))
                            break;
                      x2 = x + _spatium;
                      y2 = y;
                      bb |= QRectF(x, y, x2-x, y2-y);
                      }
                else if (pitch < _points[pt+1].pitch) {
                      // up
                      x2 = x + _spatium*.5;
                      y2 = -notePos.y() -_spatium * 2;
                      qreal dx = x2 - x;
                      qreal dy = y2 - y;

                      QPainterPath path;
                      path.moveTo(x, y);
                      path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
                      bb |= path.boundingRect();

                      bb |= arrowUp.translated(x2, y2 + _spatium * .2).boundingRect();

                      int idx = (_points[pt+1].pitch + 12)/25;
                      const char* l = label[idx];
                      QRectF r;
                      bb |= fm.boundingRect(QRectF(x2, y2, 0, 0),
                         Qt::AlignHCenter | Qt::AlignBottom | Qt::TextDontClip, QString(l));
                      }
                else {
                      // down
                      x2 = x + _spatium*.5;
                      y2 = y + _spatium * 3;
                      qreal dx = x2 - x;
                      qreal dy = y2 - y;

                      QPainterPath path;
                      path.moveTo(x, y);
                      path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
                      bb |= path.boundingRect();

                      bb |= arrowDown.translated(x2, y2 - _spatium * .2).boundingRect();
                      }
                x = x2;
                y = y2;
                }
          bb.adjust(-_lw, -_lw, _lw, _lw);
          setbbox(bb);
          setPos(0.0, 0.0);
          adjustReadPos();
          }

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

    void Bend::draw(QPainter* painter) const
          {
          QPen pen(curColor(), _lw, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin);
          painter->setPen(pen);
          painter->setBrush(QBrush(curColor()));

          qreal _spatium = spatium();
          QFont f = font(_spatium * MScore::pixelRatio);
          painter->setFont(f);

          int n    = _points.size();
          qreal x  = noteWidth;
          qreal y  = -_spatium * .8;
          qreal x2, y2;

          qreal aw = _spatium * .5;
          QPolygonF arrowUp;
          arrowUp << QPointF(0, 0) << QPointF(aw*.5, aw) << QPointF(-aw*.5, aw);
          QPolygonF arrowDown;
          arrowDown << QPointF(0, 0) << QPointF(aw*.5, -aw) << QPointF(-aw*.5, -aw);
          QFontMetrics fm(f);
          for (int pt = 0; pt < n; ++pt) {
                if (pt == (n-1))
                      break;
                int pitch = _points[pt].pitch;
                if (pt == 0 && pitch) {
                      y2 = -notePos.y() -_spatium * 2;
                      x2 = x;
                      painter->drawLine(QLineF(x, y, x2, y2));

                      painter->setBrush(curColor());
                      painter->drawPolygon(arrowUp.translated(x2, y2));

                      int idx = (pitch + 12)/25;
                      const char* l = label[idx];
                      QString s(l);
                      qreal textWidth = fm.width(s);
                      qreal textHeight = fm.height();
                      painter->drawText(QRectF(x2 - textWidth / 2, y2 - textHeight / 2, .0, .0), Qt::AlignVCenter|Qt::TextDontClip, s);

                      y = y2;
                      }
                if (pitch == _points[pt+1].pitch) {
                      if (pt == (n-2))
                            break;
                      x2 = x + _spatium;
                      y2 = y;
                      painter->drawLine(QLineF(x, y, x2, y2));
                      }
                else if (pitch < _points[pt+1].pitch) {
                      // up
                      x2 = x + _spatium*.5;
                      y2 = -notePos.y() -_spatium * 2;
                      qreal dx = x2 - x;
                      qreal dy = y2 - y;

                      QPainterPath path;
                      path.moveTo(x, y);
                      path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
                      painter->setBrush(Qt::NoBrush);
                      painter->drawPath(path);

                      painter->setBrush(curColor());
                      painter->drawPolygon(arrowUp.translated(x2, y2 ));

                      int idx = (_points[pt+1].pitch + 12)/25;
                      const char* l = label[idx];
                      qreal ty = y2; // - _spatium;
                      painter->drawText(QRectF(x2, ty, .0, .0),
                         Qt::AlignHCenter | Qt::AlignBottom | Qt::TextDontClip, QString(l));
                      }
                else {
                      // down
                      x2 = x + _spatium*.5;
                      y2 = y + _spatium * 3;
                      qreal dx = x2 - x;
                      qreal dy = y2 - y;

                      QPainterPath path;
                      path.moveTo(x, y);
                      path.cubicTo(x+dx/2, y, x2, y+dy/4, x2, y2);
                      painter->setBrush(Qt::NoBrush);
                      painter->drawPath(path);

                      painter->setBrush(curColor());
                      painter->drawPolygon(arrowDown.translated(x2, y2));
                      }
                x = x2;
                y = y2;
                }
          }

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

    void Bend::write(XmlWriter& xml) const
          {
          xml.stag("Bend");
          for (const PitchValue& v : _points) {
                xml.tagE(QString("point time=\"%1\" pitch=\"%2\" vibrato=\"%3\"")
                   .arg(v.time).arg(v.pitch).arg(v.vibrato));
                }
          for (auto k : styledProperties)
                writeProperty(xml, k.propertyIdx);
          writeProperty(xml, P_ID::PLAY);
          Element::writeProperties(xml);
          xml.etag();
          }

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

    void Bend::read(XmlReader& e)
          {
          while (e.readNextStartElement()) {
                const QStringRef& tag(e.name());

                bool found = false;
                for (auto k : styledProperties) {
                      if (readProperty(tag, e, k.propertyIdx)) {
                            setPropertyFlags(k.propertyIdx, PropertyFlags::UNSTYLED);
                            found = true;
                            break;
                            }
                      }
                if (found)
                      continue;
                if (tag == "point") {
                      PitchValue pv;
                      pv.time    = e.intAttribute("time");
                      pv.pitch   = e.intAttribute("pitch");
                      pv.vibrato = e.intAttribute("vibrato");
                      _points.append(pv);
                      e.readNext();
                      }
                else if (tag == "play") {
                      setPlayBend(e.readBool());
                      }
                else if (!Element::readProperties(e))
                      e.unknown();
                }
          }

    //---------------------------------------------------------
    //   getPropertyStyle
    //---------------------------------------------------------

    StyleIdx Bend::getPropertyStyle(P_ID id) const
          {
          for (auto k : styledProperties) {
                if (k.propertyIdx == id)
                      return k.styleIdx;
                }
          return Element::getPropertyStyle(id);
          }

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

    QVariant Bend::getProperty(P_ID id) const
          {
          switch (id) {
                case P_ID::FONT_FACE:
                      return fontFace;
                case P_ID::FONT_SIZE:
                      return fontSize;
                case P_ID::FONT_BOLD:
                      return fontBold;
                case P_ID::FONT_ITALIC:
                      return fontItalic;
                case P_ID::FONT_UNDERLINE:
                      return fontUnderline;
                case P_ID::PLAY:
                      return bool(playBend());
                default:
                      return Element::getProperty(id);
                }
          }

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

    bool Bend::setProperty(P_ID id, const QVariant& v)
          {
          switch (id) {
                case P_ID::FONT_FACE:
                      fontFace = v.toString();
                      break;
                case P_ID::FONT_SIZE:
                      fontSize = v.toReal();
                      break;
                case P_ID::FONT_BOLD:
                      fontBold = v.toBool();
                      break;
                case P_ID::FONT_ITALIC:
                      fontItalic = v.toBool();
                      break;
                case P_ID::FONT_UNDERLINE:
                      fontUnderline = v.toBool();
                      break;
                case P_ID::PLAY:
                     setPlayBend(v.toBool());
                     break;
                default:
                      return Element::setProperty(id, v);
                }
          triggerLayout();
          return true;
          }

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

    QVariant Bend::propertyDefault(P_ID id) const
          {
          for (auto k : styledProperties) {
                if (k.propertyIdx == id)
                      return score()->styleV(k.styleIdx);
                }
          switch (id) {
                case P_ID::PLAY:
                      return true;
                default:
                      return Element::propertyDefault(id);
                }
          }

    //---------------------------------------------------------
    //   resetProperty
    //---------------------------------------------------------

    void Bend::resetProperty(P_ID id)
          {
          setPropertyFlags(id, PropertyFlags::STYLED);
          }

    //---------------------------------------------------------
    //   reset
    //---------------------------------------------------------

    void Bend::reset()
          {
          for (auto k : styledProperties)
                undoResetProperty(k.propertyIdx);
          Element::reset();
          }

    //---------------------------------------------------------
    //   propertyFlags
    //---------------------------------------------------------

    PropertyFlags Bend::propertyFlags(P_ID id) const
          {
          int i = 0;
          for (auto k : styledProperties) {
                if (k.propertyIdx == id)
                      return propertyFlagsList[i];
                ++i;
                }
          return Element::propertyFlags(id);
          }

    //---------------------------------------------------------
    //   setPropertyFlags
    //---------------------------------------------------------

    void Bend::setPropertyFlags(P_ID id, PropertyFlags f)
          {
          int i = 0;
          for (auto k : styledProperties) {
                if (k.propertyIdx == id) {
                      propertyFlagsList[i] = f;
                      return;
                      }
                ++i;
                }
          Element::setPropertyFlags(id, f);
          }

    }

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