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

#ifndef __HAIRPIN_H__
#define __HAIRPIN_H__

#include "element.h"
#include "dynamic.h"
#include "line.h"
#include "textlinebase.h"
#include "mscore.h"

namespace Ms {

class Score;
class Hairpin;

enum class HairpinType : signed char {
      INVALID = -1,
      CRESC_HAIRPIN,
      DECRESC_HAIRPIN,
      CRESC_LINE,
      DECRESC_LINE
      };

enum class VeloChangeMethod : signed char {
      NORMAL,
      EXPONENTIAL,
      EASE_IN,
      EASE_OUT,
      EASE_IN_OUT       // and shake it all about
      };

//---------------------------------------------------------
//   @@ HairpinSegment
//---------------------------------------------------------

class HairpinSegment final : public TextLineBaseSegment {
      bool    drawCircledTip;
      QPointF circledTip;
      qreal   circledTipRadius;

      virtual void startEdit(EditData&) override;
      virtual void startEditDrag(EditData&) override;
      virtual void editDrag(EditData&) override;
      virtual void updateGrips(EditData&) const override;

      virtual void draw(QPainter*) const override;
      virtual Sid getPropertyStyle(Pid) const override;

      bool acceptDrop(EditData&) const override;
      Element* drop(EditData&);

   public:
      HairpinSegment(Spanner* sp, Score* s);
      virtual HairpinSegment* clone() const override { return new HairpinSegment(*this);    }
      virtual ElementType type() const override      { return ElementType::HAIRPIN_SEGMENT; }

      Hairpin* hairpin() const                       { return (Hairpin*)spanner();          }

      virtual Element* propertyDelegate(Pid) override;

      virtual void layout() override;
      virtual Shape shape() const override;
      };

//---------------------------------------------------------
//   @@ Hairpin
//   @P dynRange     enum (Dynamic.STAFF, Dynamic.PART, Dynamic.SYSTEM)
//   @P hairpinType  enum (Hairpin.CRESCENDO, Hairpin.DECRESCENDO)
//   @P veloChange   int
//---------------------------------------------------------

class Hairpin final : public TextLineBase {
      HairpinType _hairpinType { HairpinType::INVALID };
      int _veloChange;
      bool  _hairpinCircledTip;
      Dynamic::Range _dynRange;
      bool _singleNoteDynamics;
      VeloChangeMethod _veloChangeMethod;

      Spatium _hairpinHeight;
      Spatium _hairpinContHeight;

      virtual Sid getPropertyStyle(Pid) const override;

      struct VeloMethodItem {
            VeloChangeMethod method;
            const char* name;
            };

   public:
      Hairpin(Score* s);
      virtual Hairpin* clone() const override   { return new Hairpin(*this); }
      virtual ElementType type() const override { return ElementType::HAIRPIN;  }

      HairpinType hairpinType() const           { return _hairpinType; }
      void setHairpinType(HairpinType val);

      Segment* segment() const                  { return (Segment*)parent(); }
      virtual void layout() override;
      virtual LineSegment* createLineSegment() override;

      bool hairpinCircledTip() const            { return _hairpinCircledTip; }
      void setHairpinCircledTip(bool val)       { _hairpinCircledTip = val; }

      int veloChange() const                    { return _veloChange; }
      void setVeloChange(int v)                 { _veloChange = v;    }

      Dynamic::Range dynRange() const           { return _dynRange; }
      void setDynRange(Dynamic::Range t)        { _dynRange = t;    }

      Spatium hairpinHeight() const             { return _hairpinHeight; }
      void setHairpinHeight(Spatium val)        { _hairpinHeight = val; }

      Spatium hairpinContHeight() const         { return _hairpinContHeight; }
      void setHairpinContHeight(Spatium val)    { _hairpinContHeight = val; }

      bool singleNoteDynamics() const           { return _singleNoteDynamics; }
      void setSingleNoteDynamics(bool val)      { _singleNoteDynamics = val; }

      VeloChangeMethod veloChangeMethod() const { return _veloChangeMethod; }
      void setVeloChangeMethod(VeloChangeMethod val)  { _veloChangeMethod = val; }
      static QString veloChangeMethodToName(VeloChangeMethod method);
      static VeloChangeMethod nameToVeloChangeMethod(QString name);

      bool isCrescendo() const   { return _hairpinType == HairpinType::CRESC_HAIRPIN || _hairpinType == HairpinType::CRESC_LINE; }
      bool isDecrescendo() const { return _hairpinType == HairpinType::DECRESC_HAIRPIN || _hairpinType == HairpinType::DECRESC_LINE; }

      virtual void write(XmlWriter&) const override;
      virtual void read(XmlReader&) override;

      virtual QVariant getProperty(Pid id) const override;
      virtual bool setProperty(Pid propertyId, const QVariant&) override;
      virtual QVariant propertyDefault(Pid id) const override;
      virtual Pid propertyId(const QStringRef& xmlName) const override;

      virtual QString accessibleInfo() const override;
      bool isLineType() const  { return _hairpinType == HairpinType::CRESC_LINE || _hairpinType == HairpinType::DECRESC_LINE; }

      static const std::vector<VeloMethodItem> veloChangeMethodTable;
      };

}     // namespace Ms

Q_DECLARE_METATYPE(Ms::HairpinType);

#endif

