//=========================================================
//  MusE
//  Linux Music Editor
//    $Id: items.h,v 1.1.1.1 2003/10/29 10:05:29 wschweer Exp $
//  (C) Copyright 1999,2000 Werner Schweer (ws@seh.de)
//=========================================================

#ifndef __ITEMS_H__
#define __ITEMS_H__

#include <qrect.h>
#include <qpainter.h>
#include <stdio.h>
#include <list>
#include <map>

#include "symbols.h"

class MidiEvent;
class MidiPart;
class QPixmap;
class NKey;
class Scale;
class Attribute;
class StaveRow;
class SystemLayout;
class MidiEditor;

//---------------------------------------------------------
//   ScoreItem
//    represents an object in the score layout
//---------------------------------------------------------

class ScoreItem {
   public:
      enum State {Normal, Selected, Moving};

   protected:
      StaveRow* sr;
      QPoint _offset;
      State _state;
      int _tick;        // sort key
      QPoint _moving;   // Position of Object while moving
      mutable QRect  r; // bounding box relative to pt
      QPoint pt;        // Position of Object in StaveRow coordinates

   public:
      ScoreItem(int t);
      ScoreItem(int t, const QPoint&);
      ScoreItem(int t, StaveRow* sr);
      StaveRow* staveRow() const      { return sr;      }
      void setStaveRow(StaveRow* _sr) { sr = _sr;       }
      int tick() const                { return _tick;   }
      void setTick(int n)             { _tick = n;      }
      State state() const             { return _state;  }
      void setState(State s)          { _state = s;     }
      void setMoving(const QPoint& p) { _moving = p;    }
      QPoint moving() const           { return _moving; }
      QPoint pos() const              { return pt;      }
      void setPos(const QPoint& d)    { pt = d;         }
      void setPos(int x, int y)       { pt.setX(x); pt.setY(y); }
      void setXPos(int x)             { pt.setX(x); }
      void setYPos(int y)             { pt.setY(y); }
      void setBBox(int x, int y, int w, int h) { r.setRect(x,y,w,h); }

      void moveX(int dx);
      bool intersects(const QRect& rr) const { return rr.intersects(r); }
      bool contains(const QPoint& p) { return r.contains(p); }
      bool isSelected() const { return _state == Selected; }

      virtual ~ScoreItem() {}
      virtual void quantize(int, int, int) {}
      virtual void setEnh(int)     {}
      virtual void draw(QPainter&) const {}
      virtual void print(FILE*) const    {}
      virtual void remove()     {}
      virtual void place(int)      {}
      virtual MidiEvent* event() const   { return 0; }

      virtual void move(MidiEditor*, SystemLayout*, bool) {}

      QPoint offset() const           { return _offset; }
      void setOffset(const QPoint& p) { _offset = p; }
      };

class Tie;

//-----------------------------------------------
//    Note und Ghost-Note
//-----------------------------------------------

class NoteItem : public ScoreItem {
      MidiEvent* _event;
      MidiPart* _part;
      int _stem;        // Notenhals
      int _head;
      int _len;
      int _hline;       // h-Linie innerhalb des Liniensystems
      Tie* _tieTo;
      Tie* _tieFrom;
      bool _ghost;
      int _prefix;       // accidental: 0-none, 1-sharp, 2-flat, 3-norm
      bool _flags;      // draw flags if true

   public:
      NoteItem(int t, MidiEvent* e, MidiPart* part, bool flag = false);

      bool ghost() const        { return _ghost; }
      void setGhost(bool f)     { _ghost = f; }
      void setAccidental(int i) { _prefix = i; }
      int accidental() const    { return _prefix; }
      bool flags() const        { return _flags; }
      void setFlags(bool f)     { _flags = f; }

      void setTieTo(Tie*);
      void setTieFrom(Tie* t) { _tieFrom = t; }
      Tie* tieTo() const      { return _tieTo;   }
      Tie* tieFrom() const    { return _tieFrom;   }

      void setHLine(int n)    { _hline = n;    }
      int hline() const       { return _hline; }
      bool isStemDown() const { return _stem < 0; }
      int stem() const        { return _stem; }

      void stemDown(bool f)  {
            if ((f && _stem > 0) || (!f && _stem < 0))
                  _stem = -_stem;
            }
      void setStem(int n) {
            _stem = (_stem < 0) ? -n : n;
            }
      int head() const     { return _head; }
      void setHead(int n)  { _head = n; }

      int len() const      { return _len; }
      void setLen(int n)   { _len = n; }

      MidiPart* part() const   { return _part; }

      virtual void quantize(int start_tick, int nq, int rq);
      virtual MidiEvent* event() const { return _event; }
      void setEvent(MidiEvent* e) { _event = e; }
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      virtual void remove();
      virtual void move(MidiEditor*, SystemLayout*, bool);
      };

//-----------------------------------------------
//    Tie
//-----------------------------------------------

class Tie : public ScoreItem {
      NoteItem* note1;
      NoteItem* note2;
      bool _up;

   public:
      Tie(int tick, NoteItem* n1, NoteItem* n2)
         : ScoreItem(tick) {
            note1 = n1;
            note2 = n2;
            _up   = true;
            }
      void setUp(bool f)             { _up = f; }
      bool up() const                { return _up; }
      NoteItem* startNote() const    { return note1; }
      NoteItem* endNote() const      { return note2; }
      void setStartNote(NoteItem* i) { note1 = i; }
      void setEndNote(NoteItem* i)   { note2 = i; }
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      };

//---------------------------------------------------------
//   PixmapItem
//---------------------------------------------------------

class PixmapItem : public ScoreItem {
   protected:
      const QPixmap* pm;
      QPoint po;
   public:
      PixmapItem(int tick, const QPoint&, const QPixmap*);
      PixmapItem(int tick, const QPoint&);
      void setPixmap(const QPixmap*);
      virtual void draw(QPainter& p) const;
      };

//-----------------------------------------------
//    Pause
//-----------------------------------------------

class RestItem : public PixmapItem {
      int _len;
   public:
      RestItem(int tick, const QPoint&, int len, int ticksBar);
      virtual void print(FILE* f) const;
      };

//---------------------------------------------------------
//   BracketItem
//---------------------------------------------------------

class BracketItem : public PixmapItem {
      int _h;
   public:
      BracketItem(int tick, int h)
         : PixmapItem(tick, QPoint(-10, 0), bracketBM)
            {
            _h = h;
            }
      virtual void print(FILE* f) const;
      };

//---------------------------------------------------------
//   Symbol
//---------------------------------------------------------

class Symbol : public PixmapItem {
      MidiEvent* _event;
      MidiPart* _part;
   public:
      Symbol(const QPoint&, int, MidiEvent*, MidiPart*);
      ~Symbol() {}
      virtual MidiEvent* event() const   { return _event; }
      void setEvent(MidiEvent* e) { _event = e; }
      MidiPart* part() const { return _part; }
      virtual void print(FILE* f) const;
      virtual void remove();
      virtual void move(MidiEditor*, SystemLayout*, bool);
      };

//---------------------------------------------------------
//   SystemItem
//---------------------------------------------------------

class SystemItem : public ScoreItem {
      int lines;
      int width;
   public:
      SystemItem(int tick, int l, int w)
         : ScoreItem(tick) {
            lines = l;
            width = w;
            pt = QPoint(0, 0);
            }
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      };

//-----------------------------------------------
//    MeasureItem
//-----------------------------------------------

class MeasureItem : public ScoreItem {
      int type;
      int h;
   public:
      MeasureItem(int tick, const QPoint& p, int _h, int t = 0)
         : ScoreItem(tick) {
            pt   = p;
            type = t;
            h    = _h;
            }
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      };

//---------------------------------------------------------
//   Text
//---------------------------------------------------------

class Text : public ScoreItem {
   protected:
      QColor color;
      QString s;
      const QFont font;
      int align;

   public:
      Text(int t, const QString& qs, const QFont& f, const QColor& c = Qt::black)
         : ScoreItem(t), color(c), s(qs), font(f) {
            align = QPainter::AlignLeft|QPainter::AlignBottom;
            }
      Text(int t, const QFont& f, const QColor& c = Qt::black)
         : ScoreItem(t), color(c), font(f) {
            align = QPainter::AlignLeft|QPainter::AlignBottom;
            }
      ~Text() {}
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      void setAlign(int n) { align = n; }
      void setText(const QString& txt) { s = txt; }
      QString text() const { return s; }
      void setNum(int n) { s.setNum(n); }
      };

//---------------------------------------------------------
//   QuantItem
//---------------------------------------------------------

class QuantItem : public Text {
      int nq;
      int rq;
      MidiPart* _part;
      MidiEvent* _event;

   public:
      QuantItem(int t, MidiEvent*, MidiPart*, int n, int r);
      MidiPart* part() const { return _part; }
      int noteQuant() const { return nq; }
      int restQuant() const { return rq; }
      virtual MidiEvent* event() const { return _event; }
      virtual void print(FILE*) const {}
      virtual void remove();
      };

class TrackNameItem : public Text {
   public:
      TrackNameItem(int t, const QString& ps, const QFont& f)
         : Text(t, ps, f) { }
      };

class TitleItem : public Text {
   public:
      TitleItem(int t, const QString& ps, const QFont& f)
         : Text(t, ps, f) { }
      virtual void move(MidiEditor*, SystemLayout*, bool);
      };

class Comp1Item : public Text {
   public:
      Comp1Item(int t, const QString& ps, const QFont& f)
         : Text(t, ps, f) { }
      };

class Comp2Item : public Text {
   public:
      Comp2Item(int t, const QString& ps, const QFont& f)
         : Text(t, ps, f) { }
      };

class LyricsItem : public Text {
      Attribute* _attribute;        // points to Attribute in _note->event()
      NoteItem* _note;
      bool editState;
      bool cursorVisible;

   public:
      LyricsItem(const QPoint& p, Attribute* a, NoteItem* ni, const QFont&);
      Attribute* attribute() const { return _attribute; }
      NoteItem* noteItem() const { return _note; }
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      void del() { s.truncate(s.length()-1); }
      void setEditState();
      void resetEditState();
      void add(const QString& s);
      void blink();
      virtual MidiEvent* event() { return _note->event(); }
      virtual void remove();
      virtual void move(MidiEditor*, SystemLayout*, bool);
      };

//-----------------------------------------------
//    MeasureNo
//-----------------------------------------------

class MeasureNo : public Text {
   public:
      MeasureNo(int tick, const QPoint& p, int i, const QFont& f)
         : Text(tick, f) {
            pt = p;
            setNum(i+1);
            }
      };

//---------------------------------------------------------
//   KeyItem
//---------------------------------------------------------

class KeyItem : public ScoreItem {
      NKey* key;

   public:
      KeyItem(const QPoint& p, int tick, NKey* k)
         : ScoreItem(tick) {
            pt = p;
            key = k;
            }
      ~KeyItem() {}
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      };

//---------------------------------------------------------
//   TimesigItem
//---------------------------------------------------------

class TimesigItem : public ScoreItem {
      int type;
      int nom1, nom2, nom3, denom;
      QFont font;

   public:
      TimesigItem(const QPoint& p, int tick, int t, int n1, int n2, int n3, int d)
         : ScoreItem(tick) {
            pt = p;
            type = t;
            nom1 = n1;
            nom2 = n2;
            nom3 = n3;
            denom = d;
            font  = QFont(QString("Carter"), 18, QFont::Normal);
            }
      ~TimesigItem() {}
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      };

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

class Clef : public ScoreItem {
      Scale* scale;
      NKey* key;

   public:
      Clef(const QPoint& p, int tick, Scale* s, NKey* k)
         : ScoreItem(tick) {
            scale = s;
            pt    = p;
            key   = k;
            }
      ~Clef() {}
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      };

//-----------------------------------------------
//    ScoreList
//-----------------------------------------------

class ScoreList: public std::multimap<int, ScoreItem*, std::less<int> > {
   public:
      ScoreList() {}
      ~ScoreList() { clear(); }
      void clear();
      ScoreItem* find(const QPoint& pos) const;
      ScoreList::iterator add(ScoreItem* i) {
            return insert(std::pair<const int, ScoreItem*>(i->tick(), i));
            }
      };

class NoteList: public std::list<NoteItem*> {
   public:
      };

typedef ScoreList::iterator iScore;
typedef ScoreList::const_iterator ciScore;

typedef NoteList::iterator iNote;
typedef NoteList::const_iterator ciNote;

//---------------------------------------------------------
//   Beam
//---------------------------------------------------------

class Beam : public ScoreItem {
      NoteList notes;
      int min, max;
   public:
      Beam(int tick, int _min, int _max) : ScoreItem(tick) {
            min = _min;
            max = _max;
            }
      void addNote(NoteItem* item) { notes.push_back(item); }
      virtual void draw(QPainter&) const;
      virtual void print(FILE* f) const;
      };

#endif

