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

#include <stdio.h>
#include <assert.h>
#include <qpainter.h>

#include "items.h"
#include "layout.h"
#include "symbols.h"
#include "event.h"
#include "song.h"
#include "midithread.h"

//---------------------------------------------------------
//   NoteItem
//---------------------------------------------------------

NoteItem::NoteItem(int t, MidiEvent* e, MidiPart* part, bool flag)
   : ScoreItem(t)
      {
      _event    = e;
      _part     = part;
      _stem     = 20;
      _head     = 0;
      _len      = 0;
      _hline    = 0;
      _tieTo    = 0;
      _tieFrom  = 0;
      _ghost    = flag;
      _prefix   = 0;
      _flags    = true;
      }

//---------------------------------------------------------
//   remove
//---------------------------------------------------------

void NoteItem::remove()
      {
      midiThread->msgDeleteEvent(_event, _part);
      }

//---------------------------------------------------------
//   NoteItem::draw
//---------------------------------------------------------

#define LINED 3

void NoteItem::draw(QPainter& p) const
      {
      const int lineD = 6;

      QPoint xpt = ((_state == Moving) ? _moving : pt) + QPoint(0, _hline * LINED);

      //-------------------------------
      //  Notenkopf
      //-------------------------------

      if (_state == Selected || _state == Moving)
            p.setPen(Qt::red);
      switch (_head) {
            case 0:  break;
            case 1:
                  p.drawPixmap(xpt + QPoint(-3, -3), *note1BM);
                  break;
            case 2:
                  p.drawPixmap(xpt + QPoint(-3, -3), *note0BM);
                  break;
            case 3:
                  p.drawPixmap(xpt + QPoint(-3, -3), *note2BM);
                  break;
            default:
                  assert(false);
                  break;
            }
      if (_state == Selected || _state == Moving)
            p.setPen(Qt::black);

      //
      //-------------------------------
      //  Versetzungszeichen
      //-------------------------------
      //

      QPoint poff(-9, 0);     // Vorzeichen steht links vom Notenkopf
      poff += xpt;
      switch (_prefix) {
            case 0: break;
            case 1: sharpSprite->draw(p, poff); break;
            case 2: flatSprite->draw(p, poff); break;
            case 3: sharp2Sprite->draw(p, poff); break;
            case 4: flat2Sprite->draw(p, poff); break;
            case 5: natSprite->draw(p, poff); break;
            default: assert(false); break;
            }

      //
      //-------------------------------
      //  Hals
      //-------------------------------
      //
      if (_stem) {
            int y = xpt.y();
            int x = xpt.x() + ((_stem < 0) ? -4 : 4);
            p.save();
            p.setPen(QPen(Qt::black, 1));
            p.drawLine(x, y, x, y - _stem);
            p.restore();
            }

      //
      //-------------------------------
      //  Hilfslinien
      //-------------------------------
      //

      int yy = pt.y();
      int x  = pt.x();
      for (int l = -2; l >= _hline; l -= 2) {
            int y = yy + (l * lineD) / 2;
            p.drawLine(x - 5, y, x+5, y);
            }
      for (int l = 10; l <= _hline; l += 2) {
            int y = yy + (l * lineD) / 2;
            p.drawLine(x - 5, y, x+5, y);
            }

      //
      //-----------------------------------------
      //  Fähnchen und Verlängerungszeichen
      //-----------------------------------------
      //
      int nn = _len/96;      // 16'tel
      switch (nn) {
            case 1:
                  if (_flags && _stem) {
                        if (_stem < 0)
                              p.drawPixmap(xpt + QPoint(-4, -_stem-4-10), *flagIBM);
                        else
                              p.drawPixmap(xpt + QPoint(+4, -(_stem-4)), *flagBM);
                  }
            case 2:
                  if (_flags && _stem) {
                        if (_stem < 0)
                              p.drawPixmap(xpt + QPoint(-4, -_stem-10), *flagIBM);
                        else
                              p.drawPixmap(xpt + QPoint(+4, -_stem), *flagBM);
                        }
                  break;
            case 3:     // 1/8 + 1/16
                  if (_flags && _stem)
                        p.drawPixmap(xpt + QPoint(+4, -lineD*4), *flagBM);
                  p.drawPixmap(xpt + QPoint(+7, -1), *dotBM);
                  break;
            case 4:
            case 8:
                  break;
            case 6:
            case 12:
            case 5:     // falsch
                  p.drawPixmap(xpt + QPoint(+7, -1), *dotBM);
                  break;
            case 7:
            case 14:
                  p.drawPixmap(xpt + QPoint(+7, -1), *dotBM);
                  p.drawPixmap(xpt + QPoint(+11, -1), *dotBM);
                  break;
            default:
//                  printf("kann Notenlänge %d nicht verarbeiten\n", nn);
                  break;
            }
      }

//---------------------------------------------------------
//   quantize(startTick, nq, rq)
//---------------------------------------------------------

void NoteItem::quantize(int, int, int rq)
      {
      _len  = ((_event->lenTick() + rq/2)/rq)*rq;
      if (_len == 0)
            _len = rq;
      }

//---------------------------------------------------------
//   setTie
//    NoteItem is t->endNote
//    break existing tie
//---------------------------------------------------------

void NoteItem::setTieTo(Tie* t)
      {
      if (t == 0) {
            _tieTo = 0;
            return;
            }
      if (_tieTo) {
            // split tie
            if (_tieTo->endNote()->tick() > t->endNote()->tick()) {
                  _tieTo->setStartNote(t->endNote());
                  t->endNote()->setTieTo(_tieTo);
                  _tieTo = t;
                  }
            else {
                  t->setStartNote(_tieTo->endNote());
                  _tieTo->endNote()->setTieTo(t);
                  }
            }
      else {
            _tieTo = t;
            }
      }

//---------------------------------------------------------
//   move
//---------------------------------------------------------

void NoteItem::move(MidiEditor* editor, SystemLayout* system, bool copyflag)
      {
      QPoint p = _moving + _offset;
      p.setY(p.y() + _hline * LINED);
      int ry;
      int ntick  = system->xy2tick(p, &ry, sr);
      if (ntick == -1)
            return;
      int npitch = system->y2pitch(p.y());
      if (npitch == -1)
            return;

      MidiEvent* newEvent = new MidiEvent(*_event);

      newEvent->setPitch(npitch);
      newEvent->setPosTick(editor->rasterVal(ntick));
      if (copyflag) {
            midiThread->msgAddEvent(newEvent, _part, false);
            }
      else {
            midiThread->msgChangeEvent(_event, newEvent, _part, false);
            }
      }

